How to use async custom hook in Next.js middleware? - next.js

I have this custom hook:
const useRedirects = async () => {
const response = await fetch('/redirect/list')
const redirects = await response.json()
const checkRedirection = (url) => {
return {
isRedirected: // logic to check redirection
newUrl: // logic to form the new URL
}
}
return {
checkRedirection
}
}
export default useRedirects
And this is my middleware.js code:
import { NextResponse } from 'next/server'
import { useRedirect } from './UseRedirect'
export async function middleware(request) {
if (request.nextUrl.pathname.startsWith('/_next')) {
return
}
const checkRedirection = await useRedirect()
const { isRedirected, newUrl } = checkRedirection(request.nextUrl)
if (isRedirected) {
return newUrl
}
}
The problem is that, I get this error:
TypeError: Cannot read properties of null (reading 'length')
at eval (webpack-internal:///../../next/node_modules/next/dist/client/dev/error-overlay/hot-dev-client.js:262:55)
error - ../next/node_modules/#emotion/cache/dist/emotion-cache.browser.esm.js (461:0) #
error - document is not defined
So, how can I use an async hook inside my next.js middleware?

Related

How to handle next api route using dynamic id

I am using NextJS and created three layers that separate the logic.
The purpose is to minimise the error handling to the getServerSideProps section. I want to get all the lists from the database.
In the first layer, in the API route I created a folder called get-all-lists and a file [userId].js. The get request will be 'http://localhost:3000/api/get-all-lists/iudga937gr8'. Bellow there is the api route that get all the lists with the help of Prsima. It is working perfectly
import prisma from '../../../lib/prisma'
export default async function handler(req, res) {
const { userId } = req.query;
if (req.method === 'GET') {
try {
const shoppingLists = await prisma.List.findMany({ where: { userId: userId }});
res.status(200).json({lists: shoppingLists});
}
catch (error) {
console.log(error);
res.status(500).json({ message: 'Something went wrong. Please try again'});
}
}
else {
res.status(500).json({message: 'Invalid method requested!'});
}
}
The next layer, is the abstraction one which sent the final result to getServerSideProps. I created this because I need to fetch alot of requests and it would be too messy...
export const getAllLists = async userId => {
try {
const lists = await axios.get(`/api/get-all-lists/${userId}`);
return lists;
}
catch (error) {
console.log('Abstraction layer error: ', error);
return 'Something went wrong. Please try again later';
}
}
The problem arise here. In the postman I have the right result. In postman I use http://localhost:3000/api/get-all-lists/clbcpc0hi0002sb1wsiea3q5d and the server sent me the array specified.
But this function does not work and send me this error:
Abstraction layer error: TypeError [ERR_INVALID_URL]: Invalid URL
at new NodeError (node:internal/errors:371:5)
at onParseError (node:internal/url:552:9)
at new URL (node:internal/url:628:5)
at dispatchHttpRequest (file:///Users/sasdaniel/Desktop/massage/node_modules/axios/lib/adapters/http.js:176:20)
at new Promise (<anonymous>)
at http (file:///Users/sasdaniel/Desktop/massage/node_modules/axios/lib/adapters/http.js:112:10)
at Axios.dispatchRequest (file:///Users/sasdaniel/Desktop/massage/node_modules/axios/lib/core/dispatchRequest.js:51:10)
at Axios.request (file:///Users/sasdaniel/Desktop/massage/node_modules/axios/lib/core/Axios.js:142:33)
at Axios.<computed> [as get] (file:///Users/sasdaniel/Desktop/massage/node_modules/axios/lib/core/Axios.js:168:17)
at Function.wrap [as get] (file:///Users/sasdaniel/Desktop/massage/node_modules/axios/lib/helpers/bind.js:5:15) {
input: '/api/get-all-lists/clbcpc0hi0002sb1wsiea3q5d',
code: 'ERR_INVALID_URL'
}
I also tried to paste the localhost in the browser and it have no problem.
You could extract the functionality into /lib/getAllList.js:
import prisma from './prisma';
export default async function getAllLists(userId) {
return await prisma.List.findMany({ where: { userId: userId }});
}
Then use it in your API route:
import getAllLists from '../../../lib/getAllLists';
export default async function handler(req, res) {
const { userId } = req.query;
if (req.method === 'GET') {
try {
const shoppingLists = await getAllLists(userId);
res.status(200).json({lists: shoppingLists});
}
catch (error) {
console.log(error);
res.status(500).json({ message: 'Something went wrong. Please try again'});
}
}
else {
res.status(500).json({message: 'Invalid method requested!'});
}
}
Then use it in getServerSideProps:
import getAllLists from 'path/to/lib/getAllLists';
export async function getServerSideProps(context) {
const { userId } = context.params;
const shoppingLists = await getAllLists(userId);
return {
props: {
shoppingLists,
},
};
}

MSW(Mock Service Worker) in Next js first render not working

I use msw with Next js. But at First render, cannot connect api
this is index.tsx
import { useQuery } from "#tanstack/react-query";
import axios from "axios";
const Home = () => {
const getFruit = async () => {
const { data } = await axios.get("/api");
return data;
};
const { data } = useQuery(["dfa"], getFruit);
console.log("data: ", data);
return <div>Hello world</div>;
};
export default Home;
And i capture log in dev tool
In terminal compiling /_error (client and server).. error is showing.
I write code in mocks/index.ts like
async function initMocks() {
if (typeof window === "undefined") {
const { server } = await import("./server");
server.listen();
} else {
const { worker } = await import("./browser");
worker.start();
}
}
initMocks();
export {};
Also I check this code is running before index.tsx.
I think msw work late then first rendering. Is it right? How can I solve this problem?

How can I use auth0 getSession() from nextjs middleware function, or is there some other way to get user particulars via middleware

I have this code in /pages/api/_middleware.js:
import { getSession } from '#auth0/nextjs-auth0'
export default async function middleware(req, ev) {
const session = await getSession(req)
console.log(session)
return NextResponse.next()
}
Whenever I run an API call that hits this I get this message:
error - node_modules#auth0\nextjs-auth0\dist\index.browser.js?b875 (11:0) # Object.getSession
Error: The getSession method can only be used from the server side
I'm not sure it's possible with the #auth0/nextjs-auth0 lib, but I'm lazily just checking if the appSession cookie is in storage like so:
import type { NextRequest } from 'next/server'
export function middleware(req: NextRequest) {
if (req.nextUrl.pathname === '/' && req.cookies.appSession) {
return Response.redirect('/app')
}
if (req.nextUrl.pathname === '/app' && !req.cookies.appSession) {
return Response.redirect('/')
}
}
you can get the session inside of the middleware like this.
import { NextRequest, NextResponse } from 'next/server';
import { withMiddlewareAuthRequired, getSession } from '#auth0/nextjs-auth0/edge';
export default withMiddlewareAuthRequired(async (req: NextRequest) => {
const res = NextResponse.next();
const user = await getSession(req, res);
if (user) {
// Do what you want...
}
return res;
});
// only work on the '/' path
export const config = {
matcher: '/',
};
Found it here, hope it helps!
https://github.com/auth0/nextjs-auth0/blob/main/EXAMPLES.md

How to initialize router before rendering anything in Nextjs?

I'm using react-query, when I get the id from the url and try to call it inside getSubject, it passes an undefined value http://localhost:3000/api/subject/undefined
but when I click a link from another component to get in this subject component it works but if refresh the page it does not work.
const router = useRouter()
const { id } = router.query
const { data } = useQuery('subjects', async () => await getSubject(id))
return value...
}
You should use getServerSideProps in this case. It has access to query params. On top of that you can prefetch data on the server side too.
export interface PageProps {
id: string;
}
export function Page({ id }: PageProps ) {
const { data } = useQuery('subjects', async () => await getSubject(id))
}
export const getServerSideProps: GetServerSideProps<PageProps > = async ({
params,
}) => {
const { id } = params;
return {
props: {
id,
},
};
};
If you still want to use router, you can wait for router.isReady flag. When it is true, query params should be parsed.

App working locally but not on production: TypeError: Cannot read property 'titulo_categoria' of undefined

I'm trying to deploy an app using Prismic as CMS and everything works perfectly locally, but once I deploy to vercel I get the error:
19:09:51.850 | TypeError: Cannot read property 'titulo_categoria' of undefined
There seems to be something wrong when it tries to get the data from Prismic.
My code is the following:
import {getAllCategorias, getCategory2} from '../../lib/api';
export default function Index({cat}) {
return <>{cat.titulo_categoria[0].text}</>;
}
export async function getStaticProps({params}) {
const data = await getCategory2(params.slug);
return {
props: {
cat: data?.categorias ?? null,
},
};
}
export async function getStaticPaths() {
const allPosts = await getAllCategorias();
return {
paths: allPosts?.map(({node}) => `/test/${node._meta.uid}`) || [],
fallback: true,
};
}
And the API code that gets data from Prismic is:
import Prismic from 'prismic-javascript';
const REPOSITORY = process.env.PRISMIC_REPOSITORY_NAME;
const REF_API_URL = `https://${REPOSITORY}.prismic.io/api/v2`;
const GRAPHQL_API_URL = `https://${REPOSITORY}.prismic.io/graphql`;
// export const API_URL = 'https://your-repo-name.cdn.prismic.io/api/v2'
export const API_TOKEN = process.env.PRISMIC_API_TOKEN;
export const API_LOCALE = process.env.PRISMIC_REPOSITORY_LOCALE;
export const PrismicClient = Prismic.client(REF_API_URL, {
accessToken: API_TOKEN,
});
async function fetchAPI(query, {previewData, variables} = {}) {
const prismicAPI = await PrismicClient.getApi();
const res = await fetch(
`${GRAPHQL_API_URL}?query=${query}&variables=${JSON.stringify(variables)}`,
{
headers: {
'Prismic-Ref': previewData?.ref || prismicAPI.masterRef.ref,
'Content-Type': 'application/json',
'Accept-Language': API_LOCALE,
Authorization: `Token ${API_TOKEN}`,
},
}
);
if (res.status !== 200) {
console.log(await res.text());
throw new Error('Failed to fetch API');
}
const json = await res.json();
if (json.errors) {
console.error(json.errors);
throw new Error('Failed to fetch API');
}
return json.data;
}
export async function getCategory2(slug) {
const data = await fetchAPI(
`
query CategoryBySlug($slug: String!, $lang: String!) {
categorias(uid: $slug, lang: $lang) {
titulo_categoria
_meta {
uid
}
}
}
`,
{
variables: {
slug,
lang: API_LOCALE,
},
}
);
return data;
}
Any idea what's wrong with this? I been trying to figure it out for the whole day without any luck
Perhaps you already checked that, but since you mentioned everything works locally and not on Vercel are you sure your environment variables are set there? Especially PRISMIC_API_TOKEN since it appears you're relying on it to query the API?
Also I'm a bit worried about that part of the code:
props: {
cat: data?.categorias ?? null,
}
...where you might be sending a null value to your Index component resulting in your error, I'd try that instead:
props: {
cat: data?.categorias ?? {},
}
...plus using the safe navigation operator (?.) on the Index component?
Let me know how it goes!

Resources