Support for additional `Content-Type`s
See original GitHub issue_Originally posted by @KATT in https://github.com/trpc/trpc/discussions/1936#discussioncomment-2818345_
If we go down this route what we’re really talking about is straying away from JSON as the defacto mode of transport. If we do this we should also have support for some sort of binary format when doing POST
s that could take the compression further and let us have something else than content-type: application/json
.
Furthermore, I think the server should be able to receive different types of request types and be informed on what to do. I have thought about this a bit before in the context of transformers, so outlining below.
Some ideas for communicating transformers/serializer
Rough ideas below, I think best by writing code, but don’t see any of this as a final design.
contentType
-param
Goals:
- Allow for multiple content-types
- Allow for deserializing from a
Response
with abody
- Allow for serializing into a
Fetch.body
- Allow for serializing into a string for query params
When creating a server:
import { initTRPC } from '@trpc/server';
import { jsonContentType, createContentType } from '@trpc/server/content-type';
// JSON crush could be a community plugin that looks something like this:
import jsoncrush from 'jsoncrush';
const crush = createContentType({
key: 'crush',
contentType: 'application/json',
// a smarter content type would use something that could be streamed, i.e ReadableStream from `Response`
// used for `POST`:
fromResponse: async (res) => jsoncrush.uncrush(await res.text()),
fromString: (str) => jsoncrush.uncrush(str),
toBody: data => jsoncrush.crush(data), // this could allow for the types that the `Fetch API` allows - ArrayBuffer, string, [...]
// used for `GET`
toString: data => jsoncrush.data(data),
})
const trpc = initTRPC({
contentTypes: [
jsonContentType,
crush,
}
});
HTTP level
// inform server that we are sending `crush` content
GET http://localhost?content=crush&input=[...]
GET http://localhost?content=json&input=[...]
POST http://localhost?content=crush
content-type: "application/json"
// [..]
Similarly, transformer
-param could be used
import { initTRPC } from '@trpc/server';
import { defaultTransform } from '@trpc/server/transform';
// JSON crush could be a community plugin
import { crush } from 'trpc-json-crush';
const trpc = initTRPC({
transforms: [
defaultTransform, // our "no-op" trnasform
{ key: "superjson", value: superjson },
],
});
The client story
Maybe only needs to allow for one content type.
import { crush } from "~/shared/contentType"
const client = createTRPCClient({
links: [ /* ... */ ],
contentType: crush,
});
Issue Analytics
- State:
- Created a year ago
- Reactions:15
- Comments:5 (2 by maintainers)
Top GitHub Comments
+1 for this - I have a requirement to integrate with a webhook that expects a content type of
text/xml
in the response, and this is blocking me from being able to release.Is there some other way I can currently achieve this? I’m using https://github.com/jlalmes/trpc-openapi to define the HTTP path for the webhook, but AFAICT there is no way for the associated tRPC procedure to return anything other than JSON (https://github.com/jlalmes/trpc-openapi/issues/58#issuecomment-1180631200).
EDIT: If anyone is running into the same problem, specifically with a NextJS project, I solved this by just creating a Next Response Helper to completely bypass tRPC.
This has the obvious disadvantage of losing every single benefit from tRPC, but if you’re like me and just needed a single endpoint to return a different content type then it’s an easy alternative.
This would be great! I was just looking to use https://www.npmjs.com/package/notepack.io with tRPC today and came up against json being the only possible encoding