Pass data from middleware to pages
Unanswered
Virginia's Warbler posted this in #help-forum
Virginia's WarblerOP
Is it possible to pass some values from the middleware to pages (app router) as it's frequently done when using Express?
Or is there any solution to avoid performing a task (ie: a db query, headers parsing, ...) after it has already been performed in the middleware?
Or is there any solution to avoid performing a task (ie: a db query, headers parsing, ...) after it has already been performed in the middleware?
81 Replies
It is possible, however, doing that also leaks the values to client
It would be best to make a function on top of the route handler to pass the data
@Anay-208 | Ping in replies It is possible, however, doing that also leaks the values to client
Virginia's WarblerOP
you mean by adding the values to the response headers?
@Virginia's Warbler you mean by adding the values to the response headers?
yes, but it also leaks it to client
its best to make a function on top of the route handler to pass the values
@Anay-208 | Ping in replies yes, but it also leaks it to client
Virginia's WarblerOP
It doesn't seem to leak if I do the following:
... but it looks hackish...
At the same time I don't understand what's the other solution you are suggesting.
const newHeaders = new Headers(request.headers);
newHeaders.set('user', JSON.stringify(user));
return NextResponse.next({ request: { headers: newHeaders } });
... but it looks hackish...
At the same time I don't understand what's the other solution you are suggesting.
@Virginia's Warbler It doesn't seem to leak if I do the following:
const newHeaders = new Headers(request.headers);
newHeaders.set('user', JSON.stringify(user));
return NextResponse.next({ request: { headers: newHeaders } });
... but it looks hackish...
At the same time I don't understand what's the other solution you are suggesting.
If you check client headers it’s getting leaked
I’ve tried this
Virginia's WarblerOP
I should get it in Response headers in the browser, but right now I'm not getting it..
In postman I was able to view the headers
@Virginia's Warbler I should get it in Response headers in the browser, but right now I'm not getting it..
I’ll show you an screenshot on postman
Virginia's WarblerOP
are you sure you were enriching the passed request headers and not the response headers?
because I tried that before and that actually leaked
Wait, I'll get additional info and I'll answer this question after tomorrow!
Virginia's WarblerOP
super! thx
in the meantime, my screeshot where the value is used in a page.tsx but doesn't appear in the response headers
generally speaking, headers should only be values that a client provides
Virginia's WarblerOP
I agree, in fact I don't like this approach. But I also don't like having to do the same task in both middleware and pages
and I find strange there's no easy way to pass something from middleware to pages/routes, but probably I am not fully understanding the full request/response lifecycle in Next
@Virginia's Warbler and I find strange there's no easy way to pass something from middleware to pages/routes, but probably I am not fully understanding the full request/response lifecycle in Next
It’s best to create a function on top of the route handler
@Anay-208 | Ping in replies It’s best to create a function on top of the route handler
Virginia's WarblerOP
can you explain it or point me to some example, because I don't understand what you mean with that?
I’ll do when I get time
@Virginia's Warbler check this https://discord.com/channels/752553802359505017/752647196419031042/1247238263530324101
/**
* Handles POST requests by parsing the request body and validating it against a schema.
* @param handler - The handler function to be executed if the request body is valid.
* @param schema - The schema to validate the request body against.
* @returns A response after executing the function.
*/
export function routePostHandler<T>( schema: ZodSchema<T>, handler: (request: NextRequest, body : T) => Promise<NextResponse | void>) {
return async (request: NextRequest) => {
let body: T;
try {
body = await request.json();
} catch (error) {
return NextResponse.json({message: "Invalid JSON in request body"}, {status: 400});
}
const parsed = schema.safeParse(body);
if (!parsed.success) {
return NextResponse.json({message: "Invalid request body", errors: parsed.error.issues}, {status: 400});
}
const data = await handler(request, parsed.data);
return data || NextResponse.json({message: "Internal Server Error"}, {status: 500});
};
Check this, in this, its checking if type is valid. A functionality for passing data can be added into it
And it can be used in handler like this
export const POST = routePostHandler<Body>(BodySchema, async (req: NextRequest, body: Body) => {
Virginia's WarblerOP
thanks very much for the effort, but I think it doesn't solve my use case
my scenario is the following: suppose I'm using middleware to handle db based authentication (ie: in middleware I access the db to get the user, if no user no auth). I would like to have the user available in subsequent routes/pages without the need to access the db again to retrieve it, given I already did it in the middleware. The approach above doesn't seem to solve this issue, if I am not missing something.
@Virginia's Warbler my scenario is the following: suppose I'm using middleware to handle db based authentication (ie: in middleware I access the db to get the user, if no user no auth). I would like to have the user available in subsequent routes/pages without the need to access the db again to retrieve it, given I already did it in the middleware. The approach above doesn't seem to solve this issue, if I am not missing something.
You can do the authentication in higher up function
Virginia's WarblerOP
so you mean not using middleware for auth but delegating to the routes/pages?
that would be a solution, probably
I don't particularly like it, given there is a centralized place where this could be handled (ie: middleware), but it would work
@Virginia's Warbler so you mean not using middleware for auth but delegating to the routes/pages?
It’s not the best to use middleware for passing data
Virginia's WarblerOP
ok, thank you
Virginia's WarblerOP
@Anay-208 | Ping in replies Though I'm thankful for your time and effort, I don't consider it to be a valid answer to my question. The code you provided is a factory function (a HOF, to be more specific), that allows you to standardize the creation of route handlers, but doesn't in any way respond to the initial question of avoiding to perform an operation that has already been performed in the middleware. If that was the approach, a simpler solution, without recurring to HOFs (though maybe more elegant), would be to just extract a function that gets the user from db, in my example, and then use/call it in both routes and in pages (also note that the solution you propose is not applicable to pages).
Would you agree with me that having to hit the db multiple times for rendering a page, if I already hit it once for the same data during the page rendering pipeline, doesn't seem an optimal approach? As I probably wrote above, I'm coming from an Express background, and I think Express is the library that popularized the concept of middleware in the JS world, but don't quote me on that. In Express land it is/was a common pattern to enrich the request object with data collected in the middleware chain. So, for example, if I had a
Would you agree with me that having to hit the db multiple times for rendering a page, if I already hit it once for the same data during the page rendering pipeline, doesn't seem an optimal approach? As I probably wrote above, I'm coming from an Express background, and I think Express is the library that popularized the concept of middleware in the JS world, but don't quote me on that. In Express land it is/was a common pattern to enrich the request object with data collected in the middleware chain. So, for example, if I had a
requireAuth
middleware, I could safely expect to find the user in the request in a subsequent middleware or route handler, which makes a lot of sense to me. I probably don't know a lot of the magic that goes on behind the scenes in Next.js but I'd like to have an answer to my original question, which I don't seem to be able to find anywhere online.You can wait for an answer then!
Virginia's WarblerOP
🙏
Bump(for him, as I also need a answer)
Bump(for him, as I also need a answer)
Virginia's WarblerOP
@Anay-208 | Ping in replies I have not had time to find an answer to this yet, but using React's cache (
import { cache } from "react"
) seems to be an interesting path to investigate (https://youtu.be/N_sUsq_y10U?si=utUC4JCr0ysu6mn-&t=412). It sounds an interesting point to evaluate also in another use-case I have enountered, where I needed the same db data both in a Layout and in its child PageThis video will solve your pro @Anay-208 | Ping in replies
Checking it out now!
I don't use authjs, so it didn't help
Netherland Dwarf
@Virginia's Warbler Were you able to find a method that works?
@Netherland Dwarf <@560793036788072469> Were you able to find a method that works?
What's your usecase you need help with?
Probably make another post, this one is already greater than 50 messages and hence isn't very helpful for any future reference
Even I have no clue wtf is going on above lol
@Arinji What's your usecase you need help with?
Netherland Dwarf
I'm currently working on the dashboard and I plan on checking if the user is currently logged in, I'm able to do so properly and redirect them if not, but the library I'm using returns data that can be needed throughout and instead of having to refetch the data I was hoping to just pass it to the page from the middleware
I intended to use
unstable_cache
but it's unstable & I had an error using it with my libraryI would create another one but I noticed that a majority of posts like this just get ignored so I figure why not ask 😅
@Netherland Dwarf I'm currently working on the dashboard and I plan on checking if the user is currently logged in, I'm able to do so properly and redirect them if not, but the library I'm using returns data that can be needed throughout and instead of having to refetch the data I was hoping to just pass it to the page from the middleware
Issue is, middleware isn't meant to be used for heavy tasks
Essentially the middleware runs on every single request
And that's gonna slow your site down
A shit ton
This is coming from the nextjs devs
Netherland Dwarf
Maybe sense, would it be better to redirect the user on the server component instead of the middleware?
The thing we do, is in the middleware just check for the cookie existing, that's it. A quick check. Then in any page which needs auth data you just have a function wrapped in unstable cache and react cache
Which you can call
Unstable cache will cache the request itself, react cache will make sure the data is cached through render passes so only one request is made
Netherland Dwarf
Interesting, okay. I'll do that instead. If I decided to use react cache how can I reset it?
For example, I don't think I'll need to ever revalidate the data, but say they change their name or profile picture
You can't like reset it since it's main thing is to make sure if you call a function in multiple components, it's only called once and the rest use that
Netherland Dwarf
I seen revalidateTag or something but not sure I can set tags with react cache
How would you go about revalidating the data if they change their username for example?
@Netherland Dwarf How would you go about revalidating the data if they change their username for example?
Router.refresh() would just work with a revalidate to the unstable cache tag
React cache isn't "cache" per say, it just memorizes requests
Yes ik it's a dumb thing
Netherland Dwarf
Yeahh I was gonna use unstable cache, but throughout I had this error:
Or even better
Netherland Dwarf
So I need to find an alternative
@Netherland Dwarf Yeahh I was gonna use unstable cache, but throughout I had this error:
Access cookies outside of the unstable cache
Netherland Dwarf
I can't
unless I create a new supabase client
Should I make a new channel for this?
Yea
Ping me