blomqma / next-rest-framework

Type-safe, self-documenting APIs for Next.js
https://next-rest-framework.vercel.app
Other
131 stars 15 forks source link

Reusing auth outputs and middleware #162

Open markedwards opened 2 months ago

markedwards commented 2 months ago

This is a request for ideas. Overall the structure of next-rest-framework is a perfect companion to the App Router for detailed control of each API method. But for concerns which are global to the API, such as authentication, what's a good way to minimize redundancy? At the moment, for me, this comes down to two aspects:

The obvious solution is to build a reusable authenticationMiddleware function, and import it into every method. And to have a corresponding authenticationOutputs definition, and also import that into every method, like:

outputs([
  {
    body: z.object(),
    contentType: "application/json",
    status: 200,
  },
  ...authenticationOutputs,
])
.middleware(authenticationMiddleware)

Can this be less brittle and cumbersome, or is this the best we can do? I could implement standard Next middleware for all relevant routes, but that doesn't address the redundant outputs issue.

Happy for any recommendations. Thanks!

blomqma commented 2 months ago

Yeah this is a valid concern. Currently the way shown in your example is the best way to reuse logic for several API endpoints. Since Next.js has the global middleware functionality, that should be used also for common input validation between routes with this framework. For that, a solution could be to implement e.g. a middlewareRoute function that would in the same way as the route function for API endpoints and the common OpenAPI information would be parsed and included for the routes from there. The only difficult thing is mapping the parsed schemas from the middleware to the appropriate API endpoints which would happen based on the matcher defined for the middleware: https://nextjs.org/docs/app/building-your-application/routing/middleware#matching-paths

But this worth looking into and should have a high priority among new features 👍🏻

markedwards commented 2 months ago

Thanks for the feedback, that's useful.

markedwards commented 2 months ago

Worked on the implementation a bit more, and I'm actually pretty happy with the solution of passing a custom middleware to each API route. I hit a typing bug (#163), but having a reusable middleware function that can implement complex error handling, as well as provide a typed payload for the handler, is kind of worth the small hassle of passing it around.

What you mention is definitely interesting, but this is already pretty good.

markedwards commented 2 months ago

Another small request here is to expose the RouteMiddleware type and its associated types. That would make it a bit more convenient to define these functions abstractly for reuse.