was wondering if anyone could help with this issue I'm having learning the app router in regards to deeply nested dynamic routes.
Lets say I have an ecommerce shop which hosts multiple stores with their own available shopping modes (pickup and delivery) and would like to have the store id and shopping mode in the url: www.shop.com/store/STOREID/sm/SHOPPINGMODE
.
When first time users visit www.shop.com
they are first asked which shop they want and shopping mode (saved locally as a cookie for example) and any future visits it will redirect them from the root to the /store/STOREID/sm/SHOPPINGMODE
url as mentioned.
The other thing is that if the user has a store selected and they decide to go www.shop.com/products
it will redirect them to www.shop.com/store/STOREID/sm/SHOPPINGMODE/products
instead.
So basically any url should have store/STOREID/sm/SHOPPINGMODE
appended to it:
www.shop.com
-> choose store -> www.shop.com/store/STOREID/sm/SHOPPINGMODE
www.shop.com
-> www.shop.com/store/STOREID/sm/SHOPPINGMODE
www.shop.com/products
-> choose store -> www.shop.com/store/STOREID/sm/SHOPPINGMODE/products
www.shop.com/products
-> www.shop.com/store/STOREID/sm/SHOPPINGMODE/products
Hopefully that makes sense. What would be the most efficient way to implement this scenario? Middlewares? Redirects via config or in page? Something else?
Any help would be greatly appreciated!
I think using the scenario that you have mentioned, it's more efficient to use SHOPPINGMODE and STOREID in the same way to validate whether a user is logged in or not. Whoever your e-commerce needs to have this information, like app functionality, validating cookies in the middleware can guarantee it, like:
// config matcher to not catch routes of static content or api and with store id and shopping mode
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)',
'/((?!(store\/[0-9]*\/sm\/(pickup|delivery))).*)'
],
}
export function middleware(request: NextRequest) {
const HOME = '/'
// First verify if this cookies exist
const HAS_STORE_ID = request.cookies.has('X_STORE_ID')
const HAS_SHOPPING_MODE = request.cookies.has('X_SHOPPING_MODE')
if(HAS_STORE_ID && HAS_SHOPPING_MODE) {
// Get values
const STORE_ID = request.cookies.get('X_STORE_ID')
const SHOPPING_MODE = request.cookies.get('X_SHOPPING_MODE')
// You can verify if are valid values on database here or redirect later catching the error of page not found
verifyValidStoreCookies(STORE_ID,SHOPPING_MODE)
const url = `/store/${STORE_ID}/sm/${SHOPPING_MODE}`
return NextResponse.rewrite(new URL(url, request.url))
const { pathname } = req.nextUrl
}
if (HAS_STORE_ID) {
response.cookies.delete('X_STORE_ID')
return NextResponse.rewrite(new URL(HOME, request.url))
}
if (HAS_SHOPPING_MODE) {
response.cookies.delete('X_SHOPPING_MODE')
return NextResponse.rewrite(new URL(HOME, request.url))
}
return NextResponse.rewrite(new URL(HOME, request.url))
}
You can use path search to append any paths to the end of the request URL and to verify if they are applicable or not, like:
const prefixes = ['/shop', '/products']
const { pathname } = request.nextUrl
if (prefixes.some((prefix) => pathname.startsWith(prefix))) {
const url = `/store/${STORE_ID}/sm/${SHOPPING_MODE}` + pathname
return NextResponse.rewrite(new URL(url, request.url))
...
}
if (
!pathname.endsWith('/') &&
!pathname.match(/((?!\.products(?:\/.*)?)(?:[^/]+\/)*[^/]+\.\w+)/)
) {
...
}
You can view more methods here: https://nextjs.org/docs/app/building-your-application/routing/middleware
But it is always only one approach; it can change and be improved depending on your business rules. I hope it helps in some way.