How to add custom content type parser for Nest with Fastify - nest

I need to overwrite the content parser for application/json so my application accepts empty body. Right now it throws:
{
"statusCode": 400,
"code": "FST_ERR_CTP_EMPTY_JSON_BODY",
"error": "Bad Request",
"message": "Body cannot be empty when content-type is set to 'application/json'"
}
I'm trying with:
import { FastifyAdapter, NestFastifyApplication } from '#nestjs/platform-fastify';
import { NestFactory } from '#nestjs/core';
const fastifyAdapter = new FastifyAdapter({
addContentTypeParser: // what should go here
});
const app = await NestFactory.create<NestFastifyApplication>(AppModule, fastifyAdapter);
but I can't figure out what is expected under addContentTypeParser

To allow empty json body, you can add a content body parser like the following. Instead of throwing FST_ERR_CTP_EMPTY_JSON_BODY error, this will set request body to null.
const fastifyAdapter = new FastifyAdapter();
fastifyAdapter.getInstance().addContentTypeParser(
'application/json',
{ bodyLimit: 0 },
(_request, _payload, done) => {
done(null, null);
}
);
You can also set the request body to any value you want using the second argument of the done method.
Setting body to an empty object for example, would be look like this:
const fastifyAdapter = new FastifyAdapter();
fastifyAdapter.getInstance().addContentTypeParser(
'application/json',
{ bodyLimit: 0 },
(_request, _payload, done) => {
done(null, {});
}
);
Also, for those who are getting FST_ERR_CTP_INVALID_MEDIA_TYPE error like me, adding a catch-all content type parser for empty body requests fixes the issue.
const fastifyAdapter = new FastifyAdapter();
fastifyAdapter.getInstance()
.addContentTypeParser(
'*',
{ bodyLimit: 0 },
(_request, _payload, done) => {
done(null, null);
}
);
Tus clients, by default sends a POST request with no content-type and an empty body. Using a catch-all parser fixed my problem.

Related

PostMan is working but http is giving 404 error in flutter

I am using following code for my api. This api is working in postman but showing 404 error code in http flutter.
My flutter code:
RaisedButton(
onPressed: () {
apiCall();
},
child: Text("Press"),
)
Future apiCall() async {
var body =
jsonEncode({"filepath": "patient/reports/1602333458533-Liver.jpg"});
try {
await http
.post('http://3.6.197.52:3100/downloadFile',
headers: {"Accept": "Application/json"}, body: body)
.then((http.Response response) => print(response.statusCode));
} catch (e) {
print(e);
}
}
It is giving error code 404 .
Following is postman result:
Post Man result
You are setting the wrong headers. The Accept header is for determining which result type you expect from the server. From your screenshot (and the data) it seems quite clear, you would expect an image/jpg. On the other hand, you are missing the Content-Type header, which defines what type of data you are sending with your request, in your case application/json. So the server probably can't parse the body correctly.
Assuming, that jsonEncode is just something like JSON.stringify you should do something like the following
Future apiCall() async {
var body =
jsonEncode({"filepath": "patient/reports/1602333458533-Liver.jpg"});
try {
await http
.post('http://3.6.197.52:3100/downloadFile',
headers: {"Content-Type": "application/json"}, body: body)
.then((http.Response response) => print(response.statusCode));
} catch (e) {
print(e);
}
}

Axios interceptors don't send data to API in production Heroku app

This is part 2 of me debugging my application in production
In part 1, I managed to at least see what was causing my problem and managed to solve that.
When I send a request to my API which is hosted on Heroku using axios interceptor, every single request object looks like this in the API
{ 'object Object': '' }
Before sending out data to the API, I console.log() the transformRequest in axios and I can see that the data I am sending is actually there.
Note: I have tested this process simply using
axios.<HTTP_METHOD>('my/path', myData)
// ACTUAL EXAMPLE
await axios.post(
`${process.env.VUE_APP_BASE_URL}/auth/login`,
userToLogin
);
and everything works and I get data back from the server.
While that is great and all, I would like to abstract my request implementation into a separate class like I did below.
Does anyone know why the interceptor is causing this issue? Am I misusing it?
request.ts
import axios from "axios";
import { Message } from "element-ui";
import logger from "#/plugins/logger";
import { UsersModule } from "#/store/modules/users";
const DEBUG = process.env.NODE_ENV === "development";
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_URL,
timeout: 5000,
transformRequest: [function (data) {
console.log('data', data)
return data;
}],
});
service.interceptors.request.use(
config => {
if (DEBUG) {
logger.request({
method: config.method,
url: config.url
});
}
return config;
},
error => {
return Promise.reject(error);
}
);
service.interceptors.response.use(
response => {
console.log('axios interception response', response)
return response.data;
},
error => {
const { response } = error;
console.error('axios interception error', error)
if (DEBUG) {
logger.error(response.data.message, response);
}
Message({
message: `Error: ${response.data.message}`,
type: "error",
duration: 5 * 1000
});
return Promise.reject({ ...error });
}
);
export default service;
Login.vue
/**
* Sign user in
*/
async onClickLogin() {
const userToLogin = {
username: this.loginForm.username,
password: this.loginForm.password
};
try {
const res = await UsersModule.LOGIN_USER(userToLogin);
console.log("res", res);
this.onClickLoginSuccess();
} catch (error) {
throw new Error(error);
}
}
UsersModule (VUEX Store)
#Action({ rawError: true })
async [LOGIN_USER](params: UserSubmitLogin) {
const response: any = await login(params);
console.log('response in VUEX', response)
if (typeof response !== "undefined") {
const { accessToken, username, name, uid } = response;
setToken(accessToken);
this.SET_UID(uid);
this.SET_TOKEN(accessToken);
this.SET_USERNAME(username);
this.SET_NAME(name);
}
}
users api class
export const login = async (data: UserSubmitLogin) => {
return await request({
url: "/auth/login",
method: "post",
data
});
};
I'm not sure what you're trying to do with transformRequest but that probably isn't what you want.
A quote from the documentation, https://github.com/axios/axios#request-config:
The last function in the array must return a string or an instance of Buffer, ArrayBuffer, FormData or Stream
If you just return a normal JavaScript object instead it will be mangled in the way you've observed.
transformRequest is responsible for taking the data value and converting it into something that can actually be sent over the wire. The default implementation does quite a lot of work manipulating the data and setting relevant headers, in particular Content-Type. See:
https://github.com/axios/axios/blob/885ada6d9b87801a57fe1d19f57304c315703079/lib/defaults.js#L31
If you specify your own transformRequest then you are replacing that default, so none of that stuff will happen automatically.
Without knowing what you're trying to do it's difficult to advise further but you should probably use a request interceptor rather than transformRequest for whatever it is you're trying to do.

How to add private members to external api

Good afternoon all,
I am attempting to create a function that will automatically create a membership through my external loyalty program (through Whisqr) for the current user on my Wix.com website. I am receiving an error message stating the public key is not found.
Here is my backend code:
import {fetch} from 'wix-fetch';
import {wixData} from 'wix-data';
export function postLoyalty() {
let options ={
"headers": {
"X-Public": "pk_live_ba43e74df464cbf521dd07ee20443ff754c3afc11adc16df2594facb2147cd76"
}
}
const url = 'https://whisqr.com/api/v1.2/user/customer/';
const key = '<pk_live_ba43e74df464cbf521dd07ee20443ff754c3afc11adc16df2594facb2147cd76>';
console.log("Url: ");
return fetch(url, {method: 'post'})
.then(response => {
return response.json();
})
.then((data) => {
console.log(data);
return data;
});
}
Here is my page code:
import {postLoyalty} from 'backend/Loyalty.jsw';
import {wixData} from 'wix-data';
import wixLocation from "wix-location";
import {myFunction} from 'public/core.js';
import wixUsers from 'wix-users';
$w.onReady(function () {
let publickey = 'pk_live_ba43e74df464cbf521dd07ee20443ff754c3afc11adc16df2594facb2147cd76';
myFunction(publickey)
.then( (response) => {
console.log(response); //your base64 encoded string
})});
export function page1_viewportEnter(event) {
//Add your code for this event here:
let email = wixUsers.currentUser.getEmail();
postLoyalty(email)
.then(LoyaltyInfo => {
console.log(LoyaltyInfo)
$w("#text1").text = LoyaltyInfo.Results.Value;
})
}
Any and all feedback is greatly appreciated!
You are making a call to the URL using the POST method but you are not utilizing any of the keys, headers which you have defined.
A proper POST call which utilizes the header and body in its request will look like the below:
export function myFunction(data) {
const url = "https://whisqr.com/api/v1.2/user/customer/";
const headers = {
"Authorization": "Bearer " + key, //if api key is required like this
"Content-Type": "application/json" //the content type
};
return fetch(url, {
"method": "POST",
"headers": headers,
"body": JSON.stringify(data) //if there is a body
});
}
You said that you need to create a member on the external platform so you must be needing to send a body with the customer's data. Read the API Documentation.

Capture a Response from GET and Use it in the Next Request

I am trying to use the response of axios.get, and use it in axios.post. How can I use the response as a header in the POST request?
I tried using axios.post with headers defined in the request config:
var config = {
headers: {
'Access-Control-Allow-Origin': '*',
'user': newUser.eid,
'pass':'bd957c3fbb'
}
}
/*
const axios = require('axios')
getCrumb() {
return axios.get('https://jenkins.com/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)', config)
.then(response => {
return response
})
}
*/
/* code to get jenkins crumb */
const getJenkinsCrumb = () => {
try {
return axios.get('https://jenkins.com/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)', config)
.then((crumbValue) => {
console.log(crumbValue.data);
})
} catch (error) {
console.log(error)
}
}
getJenkinsCrumb();
I want use the response from the previous GET request (above) as a header in the POST call (below).
var crumbHeader = {
headers: {
'Access-Control-Allow-Origin': '*',
}
}
/* post api to kick off the build */
try {
return axios.post('https://abc123:bd95701859#jenkins.com/job/Non- PAR/job/Non-Prod-Jobs/job/uitest/job/TestJob/buildWithParameters?nodes=100000&clustername=clustername', crumbHeader)
.then((postKickTest) =>{
console.log(postKickTest.data);
})
} catch (error) {
console.log(error)
}
The Axios request config includes a headers property to specify the request's headers. The config can be specified as the 2nd argument of axios.post() (if using the two-argument signature) or the 3rd argument (if using the three-argument signature). This example demonstrates the two-argument signature of axios.post() that sets the headers with the dataresult of a previous request:
export default {
methods: {
async sendRequest() {
const userResp = await axios.get('https://reqres.in/api/users/2')
await axios.post('https://reqres.in/api/users', {
headers: userResp.data,
data: {
name: 'john doe',
job: 'leader',
}
})
},
}
}
demo
Side note: The Access-Control-Allow-Origin is a CORS header that can only be set by the server. It has no effect when sent from the client. It's possible you're incorrectly assuming that header is not reaching the server because it's not resolving a CORS issue.

How to change status code of headers of response in serverless framwork?

I want to response personal defined statuscode and some headers.
But I find even I change the status code to 201 the status code is still 200. and my defined header is not in headers.
my handler like:
function createResponse(status, header, body) {
return {
headers: Object.assign(header, {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json;charset=utf-8'
}),
statusCode: status,
body: JSON.stringify(body)
}
}
export const hello = async (event, context, cb) => {
const rep = {
message: 'v1.0',
event: event
};
cb(null, createResponse(201, {}, rep));
return;
};
I use serverless.yml my configuration is:
functions:
first:
handler: handlers/first.hello
events:
- http:
method: ANY
path: first
integration: lambda
How to check to correct code can change status code and response header?
I also find my headers still in response body, How to add my header part in Response headers?
If you think my intergration part have problem, can you give me correct configuration example?
Looks like you have a nested object inside headers.
Reference documentation,
https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
Here is the correct sample code to send the correct response,
exports.handler = function(event, context, callback) {
console.log('Received event:', JSON.stringify(event, null, 2));
var res ={
"statusCode": 200,
"headers": {
"Content-Type": "*/*"
}
};
res.body = "Hello, World !";
callback(null, res);
};
Hope it helps.