fastify-http-proxy: Failure with "Promise may not be fulfilled with 'undefined' - http-proxy

I am using the fastify with fastify-http-proxy with the following configuration:
const proxy = require('fastify-http-proxy');
fastify.register(proxy, {
upstream: "https://myendpoint/occm/api/azure",
prefix: '/azure',
onResponse: (request, reply, res) => {
console.log('Inside onResponse')
reply.send('New body of different length');
},
onError: (reply, error) => {
console.log('Inside onError')
reply.send(`My Error: ${error}`);
},
replyOptions: {
rewriteRequestHeaders: (originalRequest, headers) => {
console.log('Inside rewriteRequestHeaders')
return {
...headers,
};
},
},
});
I have configured a fastify route as this:
fastify.route({
method: 'GET',
url: `/azure/vsa/working-environments`,
schema: {
description: 'Trying out',
tags: ['notifications'],
security: [{
authorization: []
}],
params:{
title: "Working Env GET",
description:'Trying out...',
type: 'object',
example: 'No input',
properties: {
'accountId': {
description: "Account ID",
type: 'string'
},
},
}
},
handler: async (request, reply) => {
}
I am calling it as:
GET http://localhost:xxxx/azure/vsa/working-environments
Basically I would like to proxy the request to this endpoint:
https://myendpoint/occm/api/azure/vsa/working-environments
Now whenever I am running it, getting this error:
{"level":30,"time":1644249539394,"pid":12100,"hostname":"pradipm02-PC","requestId":"Q3T9RjI11N","req":{"method":"GET","url":"/azure/vsa/working-environments","hostname":"localhost:8092","remoteAddress":"127.0.0.1","remotePort":63308},"msg":"incoming request"}
{"level":50,"time":1644249540657,"pid":12100,"hostname":"pradipm02-PC","requestId":"Q3T9RjI11N","err":{"type":"FastifyError","message":"Promise may not be fulfilled with 'undefined' when statusCode is not 204","stack":"FastifyError: Promise may not be fulfilled with 'undefined' when statusCode is not 204\n at C:\\Users\\pradipm\\clients\\CloudManager\\cm_2\\occm\\service-infra\\notifications\\node_modules\\fastify\\lib\\wrapThenable.js:30:30\n at processTicksAndRejections (node:internal/process/task_queues:96:5)","name":"FastifyError","code":"FST_ERR_PROMISE_NOT_FULFILLED","statusCode":500},"msg":"Promise may not be fulfilled with 'undefined' when statusCode is not 204"}
Any of the console.log in the rewriteRequestHeaders, onReponse, onError are not showing up.
Any help is appreciated.

This is discussed in the following thread in fastify-http-proxy forum.
It is suggested to use fastify-reply-from instead.
That solves my issue.

Related

How to POST a request with the urlencode mode?

I'm a beginner with cypress, and I'm trying to send a POST request with mode urlencode to get the access token. This is script in postman:
const postRequest = {
url: 'https://login.microsoftonline.com/967731f1/oauth2/v2.0/token',
method: 'POST',
header: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: {
mode: 'urlencoded',
urlencoded:
[
{key: "client_id",value: "459e40d6-e96a-4c4e-833f-f43bd5d71885"},
{key: "scope",value: "api://icy-beach-05c371d10.1.azurestaticapps.net/459e40d6-e96a-4c4e-833f-f43bd5d71885/access-as-user"},
{key: "grant_type",value: "password"},
{key: "username",value: "abc#gmail.com"},
{key: "password",value: "xxxxxx"},
]
}
};
pm.sendRequest(postRequest, (error, response) => {
if (error) {
console.log(error);
}
pm.test('response should be okay to process', () => {
pm.environment.set("accesstoken_admin", response.json().access_token);
});
});
So, I do not know how to work on cypress. Does anyone help me? Many thanks!
/// <reference types="cypress"/>
describe('login and create a new client',()=>{
it('login by admin account',() => {
cy.request({
method: 'POST',
url:'https://login.microsoftonline.com/967731f1/oauth2/v2.0/token',
form: true,
body: {
client_id: "459e40d6-e96a-4c4e-833f-f43bd5d71885",
scope: "api://icy-beach-05c371d10.1.azurestaticapps.net/459e40d6-e96a-4c4e-833f-f43bd5d71885/access-as-user",
grant_type: "password",
username: "abc#gmail.com",
password: "xxxxxx",
}
}).then((res) => {
cy.log(JSON.stringify(res))
})
})
})

Passing array from POSTMAN and AJAX is different when received by ExpressJS

I am new to Express but not in programming. I am trying to pass an array via ajax from my frontend to express. On my postman, this is the array I am sending:
{
"userIds": ["xxxxxxxxxxxxxxxxxx"],
"type": "user"
}
and express is receiving req.body as:
{
userIds: [ 'xxxxxxxxxxxxxxxxxx' ],
type: 'user'
}
When I do this in Ajax:
data = {
userIds: ["xxxxxxxxxxxxxxxxxx"],
type: "user",
};
$.ajax({
type: "POST",
url: url,
headers: headerParams,
data: data,
success: function (room) {
console.log("room", room);
},
error: function (error) {
console.log("error", error);
},
});
Express is receiving:
[Object: null prototype] {
'userIds[]': 'xxxxxxxxxxxxxxxxxx',
type: 'user'
}
What am I doing wrong here? Or how should I mutate my req.body to get the desired output?
Note: I cannot do req.body.Foreach since it is saying forEach is not a function.
Note 2: req.body.userIds returns undefined
My best guess, Middleware body-parser to your rescue.
You can then access it as req.body.userIds, which will be an Array.

How/Where does nuxtjs set the authorization header

I inherited a web project from another developer who's left the company. It is built with nuxtjs and laravel, neither of which I am strong with.
In the web project, after a user goes to a login screen, types in email and password, and presses save, I can see in my developer tools that the nuxtjs framework sends a {email: "user#email.com", password: "password"} to the laravel api at https://example.project.com/api/login. The laravel api then returns a 200 response with this payload { data: { message: "Login successful.", token: "50|Fs88RPU7HON1LnBskm35O9txG0OnXDiG3x4XWILJ" }}. Everything is great so far!
Immediately after the 200 response above, NuxtJS sends another request to https://example.project.com/api/auth/user in an attempt to get information about this user. Nginx gives a 401 response. My first suspicion for why this happens is because NuxtJS sent an Authorization: Bearer undefined as shown in this screenshot of my browser dev tools
I've seen other situations with Authorization: Bearer [object object].
I want to know how does NuxtJS decide what value to provide to the Authorization http header? This is my current nuxt.config.js
export default {
// Global page headers: https://go.nuxtjs.dev/config-head
head: {
title: 'Blah',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: '' },
],
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.png' }],
},
// Auto import components: https://go.nuxtjs.dev/config-components
components: true,
// Modules: https://go.nuxtjs.dev/config-modules
modules: [
// https://go.nuxtjs.dev/axios
'#nuxtjs/axios',
'#nuxtjs/auth'
],
auth: {
redirect: {
login: '/login',
logout: '/',
callback: '/api/login',
home: '/'
},
strategies: {
local: {
endpoints: {
login: { url: '/api/login'},
user: { url: '/api/auth/user'}
},
}
},
localStorage: true
},
proxy: {
'/api': {
target: 'https://example.project.com/',
pathRewrite: { '^/api': '' },
},
},
// Axios module configuration: https://go.nuxtjs.dev/config-axios
axios: {
baseURL: 'https://example.project.com/',
credentials: true,
headers : {
common: {
'Accept' : 'application/json'
}
}
},
// Build Configuration: https://go.nuxtjs.dev/config-build
build: {
}
}
And also, this is the line of code in pages/login.vue that starts the login process:
await this.$auth.loginWith('local', { data: {email:"user#email.com",password:"password"} });
Simply add Authorization header as default header right after authorization request. Assuming that server sends access token in response the code might look like this:
const response = await this.$auth.loginWith('local', {
data: {
email: "user#email.com",
password:"password"
}
})
const { token } = response;
axios.defaults.headers.common = { Authorization: `Bearer ${token}` };
change your strategy as below to set property name of the token being returned in response.
strategies: {
local: {
token: {
property: 'token'
},
endpoints: {
login: { url: '/api/login'},
user: { url: '/api/auth/user'}
},
}
},
It will include the authorization header in all your requests using $axios.
also you might need to set propery of the user which you are returning from backend also.
This is done by a library in the background. #nuxtjs/auth or #nuxtjs/auth-next will set the token depending on your config in nuxt.config.ts.
You can find the token in the local storage in auth._token.<strategy>. To use a Bearer token in the subsequent userinfo request you might need to set:
nuxt.config.ts
auth: {
strategies: {
local: {
token: {
type: 'Bearer',
}
}
}

Getting 502 response and 'has been blocked by CORS policy' running a simple fetch request to my lambda function

Building a serverless web app on AWS with the serverless framework, I get a CORS error with a 502 response code authenticating against an AWS Cognito user pool
GET https://URL.amazonaws.com/dev/asset/ID-1178 502
index.html:1 Access to fetch at 'https://URL.amazonaws.com/dev/asset/PO-TIENDA1178' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
index.js:109 Uncaught (in promise) TypeError: Failed to fetch
An almost identical request works for another function.
And here are both ajax requests sent from the frontend:
// working just fine
async function getAllAssets() {
const getAssetsUrl = _config.api.invokeUrl + "/assets"
const response = await fetch(getAssetsUrl, {
headers: {
Authorization: authToken
},
type: "GET",
dataType: 'json',
crossDomain: true
})
}
// not working, throwing the error described above
async function getOneAsset() {
const getAssetsUrl = _config.api.invokeUrl + "/asset/" + "ID-1178"
const response = await fetch(getAssetsUrl, {
headers: {
Authorization: authToken
},
type: "GET",
dataType: 'json',
crossDomain: true
})
}
I run both functions onDocReady in the same window.
Here are the definitions in serverless.yaml:
# WORKS 👌🏽
getAssets:
name: ${self:service}-${self:provider.stage}-get-assets
handler: handler.getAssets
role: InventoryLambdaRole
events:
- http:
path: /assets
method: get
cors: true
authorizer:
arn: arn:aws:cognito-idp:eu-west-1:HARDCODED:ARN
# doesn't work
getAsset:
name: ${self:service}-${self:provider.stage}-get-asset
handler: handler.getAsset
role: InventoryLambdaRole
events:
- http:
path: /asset/{assetId}
method: get
cors: true
authorizer:
arn: arn:aws:cognito-idp:eu-west-1:HARDCODED:ARN
And here goes my function implementations in the handler.js:
// get all assets works fine:
module.exports.getAssets = function(event, context, callback) {
const params = {
TableName : 'Assets',
Select: 'ALL_ATTRIBUTES',
}
const request = documentClient.scan(params, function(err, data) {
if (err) {
console.log("Error", err)
} else {
const itemCount = data.Count
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
},
body: JSON.stringify({
itemCount: itemCount,
assets: data
}),
}
callback(null, response);
}
})
}
// get one asset doesn't work:
module.exports.getAsset = function(event, context, callback) {
const params = {
TableName : 'Assets',
Key: {
AssetId: event.pathParameters.assetId // also tried to just hardcode it like this: 'ID-1178'
}
}
const request = documentClient.get(params, function(err, data) {
if (err) {
console.log("Error", err)
} else {
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
},
body: JSON.stringify({
asset: data
}),
}
callback(null, response);
}
})
Although it's a CORS error, as you can see the origin headers are provided, and I found that in combination with the 502 status it might be something before the CORS, e.g. a problem in the function or with authorization. However, I can't see any problems with them so far.
The serverless function itself works as well when invoke it locally:
npm run sls -- invoke local --function getAsset -p test.json
Do you have any ideas what could be the issue or how to debug it?
Your issue may be as simple as having dynamodb:GetItem. This is a different permission than what listing all (ie query or scan) would be

Extjs 5 ajax PUT and DELETE methods throw 403 errors (csrf token included)

I am building a web application with django-rest-framework and extjs5.
Obviously i faced problems with django's csrf token, which i had to inlude in Extjs's Ajax requests.
But while i implemented POST method successfully, it seems that my implementation doesn't work for PUT and DELETE method.
My POST method code:
onSaveRecordBtnClick: function(){
Job_Name = this.lookupReference('Job_Name').getValue();
var csrf = Ext.util.Cookies.get('csrftoken');
Ext.Ajax.request({
url: '/jobs_api/job/',
method: "POST",
params: {
Job_Name: Job_Name,
'csrfmiddlewaretoken': csrf
},
success: function(conn, response, options, eOpts) {
var result = MyApp.util.Util.decodeJSON(conn.responseText);
if (result.success) {
alert('Job Submission Successfull');
}
else {
MyApp.util.Util.showErrorMsg(conn.responseText);
}
},
failure: function(conn, response, options, eOpts) {
MyApp.util.Util.showErrorMsg(conn.responseText);
}
});
}
This works perfectly, but when i try PUT or DELETE method i keep getting:
Request Method:DELETE
Status Code:403 FORBIDDEN
{"detail":"CSRF Failed: CSRF token missing or incorrect."}
My DELETE method:
onJobDblClick : function(grid, record, index, eOpts) {
var job_id = record.id;
var csrf = Ext.util.Cookies.get('csrftoken');
Ext.Ajax.request({
url: '/jobs_api/job/' + job_id + '/',
method: "DELETE",
params: {
'id': job_id,
'csrfmiddlewaretoken': csrf
},
success: function(conn, response, options, eOpts) {
var result = MyApp.util.Util.decodeJSON(conn.responseText);
if (result.success) {
alert('Job Deleted Successfully');
}
else {
MyApp.util.Util.showErrorMsg(conn.responseText);
}
},
failure: function(conn, response, options, eOpts) {
MyApp.util.Util.showErrorMsg(conn.responseText);
}
});
}
My job model is:
Ext.define('MyApp.model.Job', {
extend: 'MyApp.model.Base',
fields: [
{ name: 'id', type: 'int' },
{ name: 'Job_Name', type: 'string' },
],
proxy: {
type: 'rest',
url: '/jobs_api/job/',
reader: {
type: 'json',
rootProperty: 'data'
}
}
});
I don't know why this is happening. Please help!!

Resources