-
-
Notifications
You must be signed in to change notification settings - Fork 168
Feat: Fastify adapter #87
Comments
Hi @SeanCassiere - thanks for this! We can add this |
I actually forgot to mention |
@jlalmes I can try doing a PR with it if you want. I probably need to add some things before this package can use uttp anyway. |
Sorry was out of sick for the last couple of days. Will get on this tomorrow. As mentioned in your comment above, I'll match the pattern being used. Any thoughts on the uttp thing? Or shall I do what I'm currently doing by remapping the request and reply the methods to match what is used by the Node HTTP service (https://github.com/SeanCassiere/fastify-trpc-openapi-adapter/blob/master/src/fastify.ts#L37-L42). @jlalmes |
Hi @SeanCassiere, sorry for the super late reply!
If you're still keen to work on this then I think this is the route we should take :) |
Hi @jlalmes, no sweat, I should have followed up on this as well. I'll get on it 👍🏼. |
... the road so far
|
@jlalmes in the testing of the fastify adapter, I've run into a blocker which requires more intimate knowledge on how the ScenariosPlease see the two scenarios below using Fastify: 1. Reading the headers in
|
Hey @SeanCassiere, hows the blocker going? Would be awesome if we could use this |
@Asher-JH, In it's current state the adapter is certainly usable, however, it wouldn't have the 'feel' of interacting with the first party Fastify Request and Response objects, rather you'd have to drop down to using the raw ones instead. I've tried a few things to give it a shot, but I cannot understand why the Fastify methods are being stripped out when they arrive at the Need help from @jlalmes , as he's both the library author and quite a thorough understanding of how the official tRPC works. |
Looks great, thanks @SeanCassiere 🙌. Just opened this PR (#170) on your behalf - I will take a closer look over the weekend! |
Fastify's request and reply object are very funky when you try to clone them in any way. Spreading the request and reply object removes all inherited/prototype stuff from it, so that didn't work. Using Object.assign has some weird behavior if And for the request, we can pass it the original reference to Working snippet: fastify.all(`${prefix}/*`, async (request, reply) => {
const prefixRemovedFromUrl = request.url.replace(prefix, '')
request.raw.url = prefixRemovedFromUrl
return await openApiHttpHandler(
request,
Object.assign(reply, {
setHeader: (key: string, value: string | number | readonly string[]) => {
if (Array.isArray(value)) {
value.forEach((v) => reply.header(key, v))
return reply
}
return reply.header(key, value)
},
end: (body: any) => reply.send(body)
}),
)
}) |
Thanks, @keifufu, I'll be pushing up your version of the call as it does look better without the spread syntax. Overall, this Fastify Request object is proving to be quite fickle. I've also tried using It is truly quite frustrating, since accessing As of now, in its current state, the |
Just making sure you understand that with the snippet I posted the objects don't get stripped anymore. Accessing headers, cookies and such works as expected. The changes I did were not done for looks :^) |
@keifufu I appreciate the snippet you posted is not just for aesthetic purposes, but I think I may be missing something for the request object being held intact. Could you confirm in the This is the one I'm using to test it. export const createContext = async ({
req,
res,
}: // eslint-disable-next-line @typescript-eslint/require-await
CreateFastifyContextOptions): Promise<Context> => {
const requestId = uuid();
res.raw.setHeader('x-request-id', requestId);
let user: User | null = null;
console.log('createContext req.headers', req.headers);
console.log('createContext req.raw.headers', req.raw.headers);
try {
if (req.raw.headers.authorization) {
const token = req.raw.headers.authorization.split(' ')[1];
const userId = jwt.verify(token, jwtSecret) as string;
if (userId) {
user = database.users.find((_user) => _user.id === userId) ?? null;
}
}
} catch (cause) {
console.error(cause);
}
return { user, requestId };
}; You can test it using first the Swagger Docs http://localhost:3000/docs (this pipes the OpenAPI request into the trpc router), and then directly accessing the trpc query via the browser http://localhost:3000/trpc/posts.getPosts?batch=1&input=%7B%220%22%3A%7B%22json%22%3Anull%2C%22meta%22%3A%7B%22values%22%3A%5B%22undefined%22%5D%7D%7D%7D. |
@SeanCassiere The request doesn't get stripped anymore because we don't clone it (or spread, or anything). We just pass the reference from fastify. I can't do any tests right now, or for the next few days, but I was able to access headers, cookies and any other variable from inside Edit: Yes, without using |
Thanks! I'll nuke my |
Hello, |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
I'm curious as to why this hasn't been merged yet... I tested it by simply copying the file containing the plugin, registered it like in the example from the PR and it fine worked with a small modification to fix the url if it is nested in a fastify.register with a prefix: fastify.all(`${prefix}/*`, async (request, reply) => {
- const prefixRemovedFromUrl = request.url.replace(prefix, "");
+ const prefixRemovedFromUrl = request.url.replace(fastify.prefix, "").replace(prefix, "");
request.raw.url = prefixRemovedFromUrl;
return await openApiHttpHandler( Here's how I'm registering it if anyone is curious: fastify.register(
async (fastify) => {
// trpc main plugin
fastify.register(fastifyTRPCPlugin, {
prefix: trpcEndpoint, // "/api/v1/trpc"
useWSS: true,
trpcOptions: { router: appRouter, createContext },
});
// tRPC OpenAPI plugin to convert tRPC routes to normal ones
fastify.register(fastifyTRPCOpenApiPlugin, {
// basePath: "/",
router: appRouter,
createContext,
});
// Register Swagger UI
fastify.register(import("@fastify/swagger"), {
mode: "static",
specification: { document: openApiDocument },
});
fastify.register(import("@fastify/swagger-ui"), {
prefix: "/docs",
uiConfig: {},
});
},
{ prefix: "/api/v1" }
); |
I'm sorry, I haven't been able to contribute and complete to this adapter because of current factors in my personal life. If someone has the completed/working version of it, please push on the branch and let @jlalmes know. |
Made the changes and tested. They have been pushed onto the branch. |
Nice! I was about to push to it with those changes and a unit test; it would have been my first open source contribution haha Hopefully this gets merged soon |
Literally had an hour of off time today, and quickly pushed your code changes onto the branch. There are some package-lock merge conflicts, but as soon as they are resolved, they can be merged onto main. Edit: Have to head off now, @sylent3524 if you have time and can resolve the package-lock stuff, then it can probably be pushed today. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Looking at the open PRs now 👀 Sorry for the delay - have disabled |
Not particularly the cleanest implementation, but I got an adapter working for Fastify.
https://github.com/SeanCassiere/fastify-trpc-openapi-adapter/blob/master/src/fastify.ts.
Let me know what you think. It's definitely a bit jank since the
types
for Fastify'srequest
andreply
objects don't exactly overlap all the types inNodeHTTPRequest & NodeHTTPResponse
.The text was updated successfully, but these errors were encountered: