Next.js middleware always return null as body - node.js

Request has a body property, but it seems to always be null for me in middleware functions.
If reading the body is not supported in middleware it would be nice for the docs to note that, and maybe for NextRequest to throw a helpful error when the body is accessed. The current behavior is a bit confusing.
import { NextRequest, NextResponse } from "next/server";
const middleware = (req = NextRequest, ev) => {
console.log("hey", req.body); // hey null
};
export default middleware;
export const config = {
api: {
bodyParser: {
sizeLimit: "500kb",
responseLimit: "3mb",
},
},
};

Now this seems to work
Just do await res.json()

Related

Im trying to implement authentication in next.js using next-auth and next.js middleware, but im getting an error when using it in every route

Im trying to implement auth logic using this example but I am trying to implement it in every route like so
export const config = {
matcher: ['/:path*'],
};
but my browser breaks because too many requests, but when I change the matcher array to specific routes, it works, like this:
matcher: ['/teacher','/student'],
with the matcher like this, auth works for the pages (student,teacher) but not other pages.
middleware.ts:
import { NextRequest, NextResponse } from 'next/server';
import { withAuth } from 'next-auth/middleware';
const PUBLIC_FILE = /\.(.*)$/;
export default withAuth(
async function middleware(req: NextRequest) {
if (
req.nextUrl.pathname.startsWith('/_next') ||
req.nextUrl.pathname.includes('/api/') ||
PUBLIC_FILE.test(req.nextUrl.pathname)
) {
return;
}
if (req.nextUrl.locale === 'default') {
const locale = req.cookies.get('NEXT_LOCALE') || 'en';
return NextResponse.rewrite(
new URL(
`/${locale}${req.nextUrl.pathname}${req.nextUrl.search}`,
req.url,
),
);
}
},
{
callbacks: {
authorized({ req, token }) {
return !!token;
},
},
},
);
export const config = {
matcher: ['/:path*', '/teacher'],
};

How to get query result from postgraphile running as a library

I have postgraphile running as an express middleware. For example:
const pgMiddleware = postgraphile(pool, SCHEMA, postgraphileConfig);
app.use(pgMiddleware);
How to get or intercept the result of a query or mutation without having a separate client?
For example when I send the below query
query {
personById(id: 1){
firstname
}
}
I want to be able to get the data sent back inside the same express app. How can I do that?
I believe what you are asking for is to be able to execute GraphQL operations against a PostGraphile schema from other routes/middlewares in Express without needing to make additional http requests. This is called schema only usage and you will specifically want to use withPostGraphileContext to execute your request and process results:
import type { Express } from "express";
import type { Pool } from "pg";
import {
gql,
makeProcessSchemaPlugin,
postgraphile,
withPostGraphileContext,
} from "postgraphile";
import PgSimplifyInflectorPlugin from "#graphile-contrib/pg-simplify-inflector";
import type { GraphQLSchema } from "graphql";
import { graphql } from "graphql";
// Register your middlewares with express
const schemaOnlyUsageApp = (app: Express, pool: Pool) => {
let schema: GraphQLSchema;
// This plugin will execute a callback each time the PostGraphile
// GraphQl schema is rebuit.
const schemaProcessorPlugin = makeProcessSchemaPlugin((newSchema) => {
schema = newSchema;
return schema;
});
// Register the PostGraphile middleware as normal for requests on /graphql (and /graphiql)
app.use(
postgraphile(pool, "my_schema", {
simpleCollections: "omit",
dynamicJson: true,
legacyRelations: "omit",
setofFunctionsContainNulls: false,
appendPlugins: [PgSimplifyInflectorPlugin, schemaProcessorPlugin],
watchPg: true,
graphiql: true,
enhanceGraphiql: true,
showErrorStack: true,
allowExplain: true,
})
);
// custom route that will execute a predefined gql query directly against the schema
app.get("/posts", async (req, res) => {
// arbitrary gql query
const query = gql`
query posts {
posts {
edges {
node {
id
title
body
likeCount
createdAt
}
}
}
}
`;
const result = await withPostGraphileContext(
{
// Reuse your pool to avoid creating additional connections
pgPool: pool,
},
async (context) => {
// execute your query directly and get results without making
// an additional http request!
const queryResult = await graphql({
schema,
source: query.loc?.source || "",
contextValue: { ...context },
});
return queryResult;
}
);
res.send(result);
});
};
export default schemaOnlyUsageApp;

res.setHeader() not working as it is supposed to and not returning cookies in Next JS [duplicate]

I have to send current language on endpoint. But getting language from Cookie returns undefined inside getServerSideProps.
export async function getServerSideProps(context) {
const lang = await Cookie.get('next-i18next')
const res = await fetch(`endpoint/${lang}`)
const data = await res.json()
return {
props: { data },
}
}
export default Index;
What is the proper way to get cookie inside getServerSideProps?
You can get the cookies from the req.headers inside getServerSideProps:
export async function getServerSideProps(context) {
const cookies = context.req.headers.cookie;
return {
props: {},
};
}
You could then use the cookie npm package to parse them:
import * as cookie from 'cookie'
export async function getServerSideProps(context) {
const parsedCookies = cookie.parse(context.req.headers.cookie);
return { props: {} }
}
To avoid having to parse the cookies string from context.req.headers.cookie, Next.js also provides the cookies as an object which can be accessed with context.req.cookies.
export async function getServerSideProps(context) {
const lang = context.req.cookies['next-i18next']
// ...
}
From getServerSideProps documentation:
The req in the context passed to getServerSideProps provides built in
middleware that parses the incoming request (req). That middleware is:
req.cookies - An object containing the cookies sent by the request.
Defaults to {}
You can use parseCookies function with cookie package
import cookie from "cookie"
function parseCookies(req){
return cookie.parse(req ? req.headers.cookie || "" : document.cookie);
}
And then get access like that.
export async function getServerSideProps({ req} ) {
const cookies = parseCookies(req);
// And then get element from cookie by name
return {
props: {
jwt: cookies.jwt,
}
}
}
If you are using Axios this is very simple
This will work inside getServerSideProps method. You can't get access to the cookie by using withCredentials because this is on the server.
const { token } = context.req.cookies;
const response = await axios.get('/staff/single', {
headers: { Cookie: `token=${token};` },
});
or try (This will work on the client)
const response = await axios.get('/staff/single', {
headers: { withCredentials: true },
});
how are you doing?
you can use Something like this :
export async function getServerSideProps(context) {
console.log(context.req.cookies)
}
so easy and so beautifuly!

Next.js not build when using getStaticPaths and props

I'm trying to run next build when using getStaticProps and getStaticPaths method in one of my routes, but it fails every time. Firstly, it just couldn't connect to my API (which is obvious, they're created using Next.js' API routes which are not available when not running a Next.js app). I thought that maybe running a development server in the background would help. It did, but generated another problems, like these:
Error: Cannot find module for page: /reader/[id]
Error: Cannot find module for page: /
> Build error occurred
Error: Export encountered errors on following paths:
/
/reader/1
Dunno why. Here's the code of /reader/[id]:
const Reader = ({ reader }) => {
const router = useRouter();
return (
<Layout>
<pre>{JSON.stringify(reader, null, 2)}</pre>
</Layout>
);
};
export async function getStaticPaths() {
const response = await fetch("http://localhost:3000/api/readers");
const result: IReader[] = await response.json();
const paths = result.map((result) => ({
params: { id: result.id.toString() },
}));
return {
paths,
fallback: false,
};
}
export async function getStaticProps({ params }) {
const res = await fetch("http://localhost:3000/api/readers/" + params.id);
const result = await res.json();
return { props: { reader: result } };
}
export default Reader;
Nothing special. Code I literally rewritten from the docs and adapted for my site.
And here's the /api/readers/[id] handler.
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const knex = getKnex();
const { id } = req.query;
switch (req.method) {
case "GET":
try {
const reader = await knex
.select("*")
.from("readers")
.where("id", id)
.first();
res.status(200).json(reader);
} catch {
res.status(500).end();
}
break;
}
}
Nothing special either. So why is it crashing every time I try to build my app? Thanks for any help in advance.
You should not fetch an internal API route from getStaticProps — instead, you can write the fetch code present in API route directly in getStaticProps.
https://nextjs.org/docs/basic-features/data-fetching#write-server-side-code-directly

Unit Testing NodeJs Controller with Axios

I have a controller and a request file that look like this, making the requests with axios(to an external API), and sending the controller response to somewhere else, my question is, how to apply Unit Testing to my controller function (getInfoById), how do I mock the axiosRequest since it's inside the controller?. I am using Jest and only Jest for testing(might need something else, but I'm not changing)
file: axiosFile.js
import axios from "axios"
export const axiosRequest = async (name) => {
const { data } = await axios.get("url")
return data
}
file: controllerFile.js
import { axiosRequest } from "./axiosFile"
export const getInfoById = async (name) => {
try {
const response = await axiosRequest(name)
return { status: 200, ...response }
} catch {
return { status: 500, { err: "Internal ServerError" } }
}
}
Thanks in advance.
PS: It's a Backend in NodeJs
You can mock the http calls using nock
This way you will be directly able to test your method by mocking the underlying http call. So in your case something like
const nock = require('nock')
const scope = nock(url)
.get('/somepath')
.reply(200, {
data: {
key: 'value'
},
})

Resources