Next.js middleware NextResponse host issue - node.js

I have a issue while using NextResponse middleware. The host doesn't get detected correctly. I just started a local dev server with yarn dev.
Code:
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/home')) {
return NextResponse.redirect(new URL('/test', request.url))
}
}
All this code throws an error: TypeError: Invalid URL
As I understand local server can't determine the url which comes from request.url because localhost and port part gets ignored.
Also typescript throws an error on new URL: Argument of type 'URL' is not assignable to parameter of type 'string | NextURL'.   Type 'URL' is missing the following properties from type 'NextURL': _basePath, _options, _url, absolute, and 6 more.
Any ideas how to fix it on next.js application?

Related

How to implement Faust.js Basic Http Authentication

I'm implementing Headless Wordpress using Faust.js and ran into a problem. The current Wordpress backend requires basic http authentication, protected by base64-encoded credentials, before being able to access the backend site contents and I'm running the frontend with Faust.js. On a local environment, there is no need to implement adding the credentials to the header but on production (because the http authentication exists), I can't retrieve the post content as well as other assets such as images, etc. from the Wordpress backend.
I was doing some research into how to add the http authentication but so far I've only found limited examples of how to implement basic authentication to do this. One is with typescript (https://github.com/wpengine/faustjs/issues/845) but since I currently have the project on js code, it seems I would need to convert a lot of the files into typescript (maybe including the packages included in node_modules which I don't want to break if I did the conversion). I want to find a way to add this http basic authentication as part of the request header on my Faust.js frontend project without converting to js.
On the example, I've tried implementing this with the ts example, while using js code, but I'm getting all sorts of errors, when building it. Here's the code:
import { IncomingMessage } from 'http';
import { getClient, logQueries } from '#faustjs/next';
import {
generatedSchema,
scalarsEnumsHash,
GeneratedSchema,
SchemaObjectTypes,
SchemaObjectTypesNames,
} from './schema.generated';
export const client = getClient({
GeneratedSchema,
SchemaObjectTypesNames,
SchemaObjectTypes,
schema: generatedSchema,
scalarsEnumsHash,
applyRequestContext: async (url, init) => {
const newInit = {
...init,
headers: {
...init.headers,
authorization: 'Basic YmxhbmtkZXhzaXRzdGc6OTMzODVlNjY=',
},
};
return { url, init: newInit };
},
});
export function serverClient(req) {
return getClient<GeneratedSchema, SchemaObjectTypesNames, SchemaObjectTypes>({
schema: generatedSchema,
scalarsEnumsHash,
context: req,
});
}
if (process.env.NODE_ENV === 'development') {
logQueries(client);
}
export * from './schema.generated';
The errors I'm getting when building it are among the following:
1:1 Error: There should be at least one empty line between import groups import/order
8:3 Error: GeneratedSchema not found in './schema.generated' import/named
9:3 Error: SchemaObjectTypes not found in './schema.generated' import/named
10:3 Error: SchemaObjectTypesNames not found in './schema.generated' import/named

"TypeError: Failed to parse URL from (URL).vercel.app/api/getMessages" when building Next.js 13 with TypeScript on Vercel

Hello fellow StackOverflow Community:
I'm facing this error "TypeError: Failed to parse URL from next-chat-lenx51hr5-gregory-buffard.vercel.app/api/getMessages" when trying to build my Next.js 13 app using TypeScript on Vercel. On localhost:3000 with npm run dev the app works good, but when trying to build it on Vercel the error appears. I'm a newbie noob in Next and I would really appreciate any kind of help. The error also contains a few sub-errors which are those (build log from Vercel):
TypeError: Failed to parse URL from next-chat-lenx51hr5-gregory-buffard.vercel.app/api/getMessages
22:34:29.292 at Object.fetch (node:internal/deps/undici/undici:11118:11)
22:34:29.292 at async HomePage (/vercel/path0/next-chat/.next/server/app/page.js:552:18) {
22:34:29.292 [cause]: TypeError [ERR_INVALID_URL]: Invalid URL
You can also review the getMessages.ts file down below:
import type { NextApiRequest, NextApiResponse } from "next";
import redis from "../../redis";
import { Message } from "../../typings";
type Data = {
messages: Message[];
};
type ErrorData = {
body: string;
};
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<Data | ErrorData>
) {
if (req.method !== "GET") {
res.status(405).json({ body: "Method Not Allowed" });
return;
}
const messagesRes = await redis.hvals("messages");
const messages: Message[] = messagesRes
.map((message) => JSON.parse(message))
.sort((a, b) => b.created_at - a.created_at);
res.status(200).json({ messages });
Again, Thank You for any kind of help. Also, if you need any additional files to understand the problem, please feel free to ask.
I have resolved the issue by hosting the app on a dev server instead of sending it production- completely skipping the "build" errors and problems. Thanks for everyone's interest and contributions!

ApolloError: GraphQL error: Validation error of type FieldUndefined: Field '<my query name>' in type 'Mutation' is undefined # '<my query name'

I'm trying to run a simple mutation using AppSync with aws-sdk in a NodeJS environment. I'm making an error but I can't figure it out. This query works in my AppSync console:
mutation MyMutation {
createApiKey(input: {key: "testconsole2"}) {
id
key
}
}
Then when I try it in NodeJS I can't get it work (despite all of my other similar queries working):
async function createApiKey({ encryptedKey }: { encryptedKey: string }) {
const createApiKeyQueryString = `mutation createApiKey(
$key: String!,
){
createApiKey(
input: {
key: $key
}
){
key
}
}`;
try {
const runMutation = await appSyncClient.mutate({
mutation: gql(createApiKeyQueryString),
variables: {
key: encryptedKey,
},
});
console.log({
response: runMutation // Throws error before we reach here
});
return (runMutation as { data }).data;
} catch (error) {
console.log(error); // ApolloError: GraphQL error: Validation error of type FieldUndefined: Field 'createApiKey' in type 'Mutation' is undefined # 'createApiKey
}
}
I'm making a silly error, but I can't figure out what I'm doing wrong, or what the error message means?
I was using the wrong AppSync URL (eg, "https://.appsync-api.eu-west-2.amazonaws.com/graphql").
This meant that the schema name for my ApiKey table didn't exist, which is what the following was trying to tell me:
ApolloError: GraphQL error: Validation error of type FieldUndefined:
Field 'createApiKey' in type 'Mutation' is undefined # 'createApiKey
Basically, because I hadn't deployed my ApiKey schema from my amplify.graphql file, Amplify hadn't generated the relevant AppSync calls (ie, 'createApiKey'). So when I tried to invoke the call with my NodeJS code, AppSync told me that it was undefined.

Using NodeJS & Typescript - how to access data of an object of type Request

I need to get access to
req.kauth.grant
which is populated for sure - because printing req prints me this:
kauth: {
grant: Grant {
access_token: [Token],
refresh_token: undefined,
id_token: undefined,
token_type: undefined,
expires_in: undefined,
__raw: ....
}
but if I try to directly print like this
router.get('/', keycloak.protect(), async (req:Request, res:Response):Promise<void> => {
console.log(req.kauth);
res.send("hello");
});
I get:
[ERROR] 18:32:14 ⨯ Unable to compile TypeScript:
src/api/routes/elev.ts:11:21 - error TS2339: Property 'kauth' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.
11 console.log(req.kauth);
It's my first time using Typescript with NodeJS, so if I'm missing something obvious, I'm sorry.
So, how can I access that field in this case?
Thanks :)
The problem here is that kauth is not a property in the Request type. That's what the error message is telling you. Therefore, you have two options. Either extend the Request type (search for ways to do that) or tell typescript to ignore the error by putting a // #ts-ignore line above the console.log line giving you the error message.
You should tell typescript that the Request object has the kauth property:
interface kAuthRequest extends Request {
kauth: {grant: {[key: string]: unknown}}
}
Then, instead of using type Request, you use kAuthRequest.
Or, if all Request objects will have that property, you can directly add it onto the interface:
interface Request {
kauth: {grant: {[key: string]: unknown}}
}
See the documentation for interfaces and declaration merging for more information.

Vue SSR serverPrefetch server redirect with this.$ssrContext.res.redirect

Is it possible to do a redirect from a component, in VUE SSR, without getting the error on the server console: [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client?
Code is as follows:
serverPrefetch() {
// need the data from this.fetchPage service to decide on the redirect
return this.fetchPage().then(function (response) {
// do some checks here
// THIS IS THE NODE EXPRESS REDIRECT
this.$ssrContext.res.redirect('/');
this.$ssrContext.res.end(); // with or without, same error
}.bind(this));
},
beforeMount() {
this.fetchPage();
}
NOTE: If I try to use this.$router.replace('/') (or any other methods), I get the error: [Vue warn]: Error in callback for watcher $route: ReferenceError: document is not defined.
In my project I did the redirect on the client side, but I was wondering if this can be done also from server.
TL;DR:
Reject the serverPrefetch with {url: '/redirect-route'}
Found the solution as follows: If you implement the vue-ssr project as the https://github.com/vuejs/vue-hackernews-2.0 repo, in server/index.js you have a handleError function that has a redirect in it:
if (err.url) {
res.redirect(err.url);
}
And all you need to do in your component is:
serverPrefetch() {
return this.fetchPage().then(res => {
if(res === 'MY_REDIRECT_CONDITION') {
// !!! THE ACTUAL REDIRECT TRIGGER !!!
return Promise.reject({url: '/'});
}
});
},

Resources