In the code below I want to validate the request body with a schema from zod, currently, it will fail and catch. This is because req.body is returning a ReadableStream<Uint8Array> and not the object that it expects to parse.
export default async function middleware(req: NextRequest, res: NextResponse) {
const { pathname } = req.nextUrl;
if (pathname.startsWith('/api/user/create')) {
try {
createUserSchema.parse({
body: req.body,
params: req.nextUrl.searchParams,
});
return NextResponse.next();
} catch (error: any) {
console.log(req.body);
return NextResponse.json(
{ success: false, message: error },
{ status: 422, headers: { 'content-type': 'application/json' } }
);
}
}
return NextResponse.next();
}
this below is the output of the console.log(req.body);
<ref *1> ReadableStream {
_state: 'readable',
_reader: undefined,
_storedError: undefined,
_disturbed: false,
_readableStreamController: ReadableStreamDefaultController {
_controlledReadableStream: [Circular *1],
_queue: S {
_cursor: 0,
_size: 0,
_front: { _elements: [], _next: undefined },
_back: { _elements: [], _next: undefined }
},
_queueTotalSize: 0,
_started: false,
_closeRequested: false,
_pullAgain: false,
_pulling: false,
_strategySizeAlgorithm: [Function],
_strategyHWM: 1,
_pullAlgorithm: [Function],
_cancelAlgorithm: [Function]
}
}
I did some research and found that I need to run some kind of conversion method on this ReadableStream. The problem is that most of these include the Buffer module which cannot be run on the Edge and therefore cannot work in the middleware.ts. Is there perhaps a polyfill that I can use?
"next": "^13.0.7"
Node v16.17.0
Next.js middleware does not work the same as an Express middleware because it only runs on navigation and does not act as a catch-all for your API endpoints.
As per the documentation, you can only access cookies, access/modify request headers and perform redirects and rewrites using this feature.
You can use
const body = await req.json()
Related
So i am facing a very weird issue. I have a react native app that was working fine until yesterday night. Suddenly then my aws s3 connections stopped working. We had made no changes in the code to that code in 2 months which is why im confused.
Here is my CloudService.js
import React ,{useState} from 'react';
import AWS from 'aws-sdk'
export const S3_BUCKET_CAROUSEL ='carouselnews';
export const S3_BUCKET_ADVISORS = 'advisorsdata';
const REGION ='ap-south-1';
AWS.config.update({
accessKeyId: 'xxxxxx',
secretAccessKey: 'xxxxxx'
})
export const getCarouselData = () => {
const bucket = new AWS.S3({
params: { Bucket: S3_BUCKET_CAROUSEL},
region: REGION,
})
const S3_URL = `https://${S3_BUCKET_CAROUSEL}.s3.${REGION}.amazonaws.com/`
return bucket.listObjects().promise();
}
export const getS3URL = (bucket) => {
return `https://${bucket}.s3.${REGION}.amazonaws.com/`
}
Calling it in my Home.js like this:
(Gets executed inside useEffect but i tried moving it outside into a button too)
getCarouselData()
.then(data => {
if (data) {
var s3_url = getS3URL(S3_BUCKET_CAROUSEL);
var items = data.Contents;
items.forEach((item, index) => {
if (index > 5) {
return;
}
setcarouselItems(oldArray => [
...oldArray,
{
id: index + 1,
url: `${s3_url}${item.Key}`,
},
]);
});
}
setTimeout(() => {
setcarouselLoaded(true);
}, 4000);
})
.catch(err => {
console.log(err);
})
.finally(zz => {
console.log("whatttt")
})
Basically when the method runs, it does not return anything. Doesnt go in the catch either and i tried putting try catch inside, even there nothing happens
I checked my credential keys in AWS IAM to see if theres a problem there but according to that my keys were not used after last night atall!
Some little info, when i try to print just the bucket object, it does give a result saying that there is some interaction going on with AWS i think
Heres the response when i do console.log(bucket)
{"CALL_EVENTS_BUBBLE": [Function CALL_EVENTS_BUBBLE], "MONITOR_EVENTS_BUBBLE": [Function EVENTS_BUBBLE], "_clientId": 27, "_events": {"apiCall": [[Function CALL_EVENTS_BUBBLE]], "apiCallAttempt": [[Function EVENTS_BUBBLE]]}, "config": {"apiVersion": null, "apiVersions": {}, "clientSideMonitoring": false, "computeChecksums": true, "convertResponseTypes": true, "correctClockSkew": false, "credentialProvider": null, "credentials": {"accessKeyId": "AKIAXERRWBISWIDH64XH", "expireTime": null, "expired": false, "refreshCallbacks": [Array], "sessionToken": undefined}, "customUserAgent": null, "dynamoDbCrc32": true, "endpoint": "s3.ap-south-1.amazonaws.com", "endpointCacheSize": 1000, "endpointDiscoveryEnabled": undefined, "hostPrefixEnabled": true, "httpOptions": {"timeout": 120000}, "logger": null, "maxRedirects": 10, "maxRetries": undefined, "paramValidation": true, "params": {"Bucket": "carouselnews"}, "region": "ap-south-1", "retryDelayOptions": {}, "s3BucketEndpoint": false, "s3DisableBodySigning": true, "s3ForcePathStyle": false, "s3UsEast1RegionalEndpoint": "legacy", "s3UseArnRegion": undefined, "signatureCache": true, "signatureVersion": "v4", "sslEnabled": true, "stsRegionalEndpoints": "legacy", "systemClockOffset": 0, "useAccelerateEndpoint": false, "useDualstackEndpoint": false, "useFipsEndpoint": false}, "endpoint": {"host": "s3.ap-south-1.amazonaws.com", "hostname": "s3.ap-south-1.amazonaws.com", "href": "https://s3.ap-south-1.amazonaws.com/", "path": "/", "pathname": "/", "port": 443, "protocol": "https:"}, "isGlobalEndpoint": false}
The network call for the aws call:
According to the API documentation, to receive json as formData from a POST request, one must use body-parser. I have declared it in the gateway service but I can still not receive the formData in my action.
api.service.js
module.exports = {
name: "api",
mixins: [ApiGateway],
settings: {
port: process.env.PORT || 3000,
routes: [{
path: "/api",
aliases: {
"POST users": "users.insertUser",
},
//The API Documentation recomends using the body-parser here
bodyParsers: {
json: true,
urlencoded: { extended: true }
},
}],
// In some example they also set the body-parser here
bodyParsers: {
json: true,
urlencoded: { extended: true }
},
},
};
In the actions service.insertUser action I am supposed to receive the
req.body as ctx.params, however it is always empty
My users.service.js
actions: {
insertUser: {
handler(ctx) {
this.logger.info("posting", ctx.params); // -> prints {} instead of the formData
}
}
have you tried giving params
insertUser: {
auth: "required",
params: {
function_id: { type: "string" },
role_id: { type: "string" },
},
handler(ctx) { ctx.params.role_id
send post data with content-type:application/json
I've got a provider that uses the Http service to perform a GET operation over a localhost server:
requestAchievedCombined(config){
return new Promise( (resolve, reject) => {
const URL = "localhost:3000";
const query = "?collection=achieved_combined&query=columns";
this.http.get(URL+"/api"+query).subscribe( response => {
// TODO: check data integriy
console.log(">> API RES: ", response)
resolve(response);
}, err => this.errorHandler(err, reject));
})
}
The server is hosted in localhost:3000 and running, and it works perfectly when called from the navigator with that same GET query string... it returns some JSON.
Thing is, when I execute my Angular app, this gives me the following error:
ERROR [DataRequester] =>
{…}
_body: "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>Cannot GET /function%20URL()%20%7B%20%20%20%20[native%20code]%7D/api</pre>\n</body>\n</html>\n"
headers: Object { _headers: Map, _normalizedNames: Map }
ok: false
status: 404
statusText: "Not Found"
type: 2
url: "http://localhost:4200/function%20URL()%20%7B%20%20%20%20[native%20code]%7D/api?collection=achieved_combined&query=columns"
__proto__: Object { constructor: Response(), toString: Response.prototype.toString() }
Do anybody know why this happens? What am I doing wrong? I'm using the latest Angular version.
pd: yes I tried putting http:// before localhost in the URL.
EDIT: After changing the url to http://localhost:3000 and call the property in a proper way (I was forgetting the this. thing), I could manage to communicate with the server, but now I'm having this issue:
ERROR [DataRequester] =>
{…}
_body: error
bubbles: false
cancelBubble: false
cancelable: false
composed: false
currentTarget: null
defaultPrevented: false
eventPhase: 0
explicitOriginalTarget: XMLHttpRequest { __zone_symbol__xhrSync: false, __zone_symbol__xhrURL: "http://localhost:3000/api?collection=achieved_combined&query=columns", readyState: 4, … }
isTrusted: true
lengthComputable: false
loaded: 0
originalTarget: XMLHttpRequest { __zone_symbol__xhrSync: false, __zone_symbol__xhrURL: "http://localhost:3000/api?collection=achieved_combined&query=columns", readyState: 4, … }
target: XMLHttpRequest { __zone_symbol__xhrSync: false, __zone_symbol__xhrURL: "http://localhost:3000/api?collection=achieved_combined&query=columns", readyState: 4, … }
timeStamp: 3687.8557595446277
total: 0
type: "error"
__proto__: ProgressEventPrototype { lengthComputable: Getter, loaded: Getter, total: Getter, … }
headers: Object { _headers: Map, _normalizedNames: Map }
ok: false
status: 0
statusText: ""
type: 3
url: null
__proto__: Object { constructor: Response(), toString: Response.prototype.toString() }
URL is a global function that gets "called". Try renaming the URL var to url and it should work.
Okay, first thing wrong was that I wasn't calling the URL property in a good way: actually, it wasn't in the method but in the class, and I was forgetting the "this.", so I wasn't pointing to the right variable.
Secondly, fixed my edit simply setting up CORS in my express server:
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
Now my Angular app correctly gets the data!
I'm just passing by to give you some code
requestAchievedCombined(config): Observable<any> {
const URL = "localhost:3000";
const query = "?collection=achieved_combined&query=columns";
return this.http.get(URL+"/api"+query)
.map( response => {
// TODO: check data integriy
console.log(">> API RES: ", response)
return response;
}, err => this.errorHandler(err))
// .toPromise() // If you still want your cherished promise
;
}
I've changed your function to simplify it : you should use Observables instead of Promises. I know, I was skeptical at first too, but Observables are way more powerful than promises. and if you still don't like it, simply call .toPromise() right after the map operator, it will still be clearer ;)
Other than that, Could you post the trace of your error instead of the payload ? We need the error message to know what is happening.
Using Google's Gmail API, A module returns an auth object that I use in a Gmail object inside of my listLabelsfunction. When It's passed in it works just fine, but If I try creating that exact same object inside of the function and use that in the Gmail object it returns out this (Separate GoogleAPIs module)
error: req = authClient.request(options, callback);
^
TypeError: Object #<Object> has no method 'request'
This is what my function looks like right now:
function listLabels(auth) {
var auth1 = {
"transporter": {},
"clientId_": "75i4354355NOTID.apps.googleusercontent.com",
"clientSecret_": "NOTSECRET",
"redirectUri_": "http://notawebsite",
"opts": {},
"credentials": {
"access_token": "not.not_access_token",
"token_type": "Bearer",
"expiry_data":1441095644613
}
}
console.log("Original Auth: " + JSON.stringify(auth, null, 4));
console.log("New Auth: " + JSON.stringify(auth1, null, 4));
var gmail = google.gmail('v1');
gmail.users.labels.list({
auth: auth,
userId: 'email#email.com',
}, function(err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
var labels = response.labels;
if (labels.length == 0) {
console.log('No labels found.');
} else {
console.log('Labels:');
for (var i = 0; i < labels.length; i++) {
var label = labels[i];
console.log('- %s', label.name);
}
}
});
}
If I use the auth object passed in it works just fine, if I use auth1it doesn't work and gives me the error above.
As you can see, I've also attempted to print out both objects below:
Original Auth: {
"transporter": {},
"clientId_": "...",
"clientSecret_": "...",
"redirectUri_": "...",
"opts": {},
"credentials": {
"access_token": "...",
"token_type": "Bearer",
"expiry_date": 1441098460931
}
}
New Auth: {
"transporter": {},
"clientId_": "...",
"clientSecret_": "...",
"redirectUri_": "...",
"opts": {},
"credentials": {
"access_token": "...",
"token_type": "Bearer",
"expiry_data": 1441095644613
}
}
(Both tokens are now expired)
When Auth is logged:
{ array:
[ { [Function: OAuth2Client]
super_: [Function: AuthClient],
GOOGLE_OAUTH2_AUTH_BASE_URL_: 'https://accounts.google.com/o/oauth2/auth',
GOOGLE_OAUTH2_TOKEN_URL_: 'https://accounts.google.com/o/oauth2/token',
GOOGLE_OAUTH2_REVOKE_URL_: 'https://accounts.google.com/o/oauth2/revoke',
GOOGLE_OAUTH2_FEDERATED_SIGNON_CERTS_URL_: 'https://www.googleapis.com/oauth2/v1/certs',
CLOCK_SKEW_SECS_: 300,
MAX_TOKEN_LIFETIME_SECS_: 86400,
ISSUER_: 'accounts.google.com' },
[Function: AuthClient],
[Function: Object] ],
string: 'OAuth2Client :: AuthClient :: Object' }
Probably you're not printing the whole prototype chain. console.log doesn't do this by default, as far as I know. So the original auth has some prototype with the method request, and your "clone" doesn't. Hence the error.
Or perhaps you're simply printing it without methods somehow, and auth has the method request directly. But I think not printing the prototype is more likely.
I am trying to test a secure websocket but I'm having trouble. Here is my test:
var WebSocket = require('ws');
describe('testing Web Socket', function() {
it('should do stuff', function(done) {
var ws = new WebSocket('wss://localhost:15449/', {
protocolVersion: 8,
origin: 'https://localhost:15449'
});
ws.on('open', function() {
console.log('open!!!');
done();
});
console.log(ws);
});
});
Here's the log of "ws" after it's created:
{ domain: null,
_events: { open: [Function] },
_maxListeners: undefined,
_socket: null,
_ultron: null,
_closeReceived: false,
bytesReceived: 0,
readyState: 0,
supports: { binary: true },
extensions: {},
_isServer: false,
url: 'wss://localhost:15449/',
protocolVersion: 8 }
I don't get a log back from open. I am running the project locally and when I use the Chrome Advanced Rest Client tool I am able to connect just fine.
Am I missing something? Please help.
Edit:
I added ws.on('error') and it logged out { [Error: self signed certificate] code: 'DEPTH_ZERO_SELF_SIGNED_CERT' }
I've also tried following this code but get the same error.
The https module is rejecting your self-signed cert (as one would hope). You can force it to stop checking by passing a rejectUnauthorized: false option (which WebSocket will pass down to https):
var ws = new WebSocket('wss://localhost:15449/', {
protocolVersion: 8,
origin: 'https://localhost:15449',
rejectUnauthorized: false
});