Capture POST request body in Sentry React - reactjs

Is there a way to capture the POST request body in Sentry.io when any request fails?
I am using #sentry/react and "#sentry/tracing version ^7.16.0
const onSubmit = async ({foo, bar}: IForm) => {
try {
await fetch(
`http://localhost:3001/v1/test`,
{
method: "POST",
body: JSON.stringify({
foo,
bar,
}),
headers: { "Content-Type": "application/json" },
}
);
} catch (err) {
Sentry.captureException(err);
}
}
It looks like the entire body is skipped from tracking in Sentry at all:
Sentry.init({
dsn: process.env.REACT_APP_SENTRY_DSN,
environment: process.env.REACT_APP_SENTRY_ENV,
integrations: [new BrowserTracing()],
tracesSampleRate: 1.0,
// Filtering important sensitive data before sending to Sentry.io
beforeBreadcrumb(breadcrumb, hint) {
console.log('beforeBreadcrumb breadcrumb: ', breadcrumb) // no post request body here
console.log('beforeBreadcrumb hint: ', hint) // no post request body here as well
return breadcrumb;
},
beforeSend(event, hint) {
console.log("beforeSend hint: ", hint); // no post request body here
console.log("beforeSend event: ", event); // no post request body here as well
return event;
},
})
And of course, there is no request body(foo/bar object) in the Sentry dashboard.
Is there any way to always add the POST request body/payload to each failed request exception?
Of course, I can add breadcrumbs before sending the request, but it would be nice to have this working by default.

Related

Getting bad request from server (Spring boot) when using axios request

I'm currently stuck sending a request to my server and can not get a response. I have tried it on postman and it runs completely fine. However, when I try to put it on react, the back-end always response with a bad request.
Here is my code for the back-end
#GetMapping(value = "/searchPatient")
public ResponseEntity<?> searchPatients(#RequestParam String id_num,
#RequestParam String name) {
List<PatientForSearchDto> patientForSearchDtos = patientService.viewSearchedPatient(id_num, name);
return ResponseEntity.status(HttpStatus.OK).body(
new ResponseObject("ok", "Success", patientForSearchDtos)
);
}
Here is my code for Front end (react)
async function sendRequest () {
const formData = new FormData();
formData.append('id_num', id_num);
formData.append('name', name);
console.log(formData)
console.log(formData.get('name'))
console.log(formData.get('id_num'))
const config = {
method: 'get',
url: 'http://localhost:8080/api/searchPatient',
// headers : {
// 'Content-Type': 'from-data'
// },
data : formData
};
await axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
setPatientList(response.data.data.object)
})
.catch(function (error) {
console.log(error);
});
}
Here is what I get when sending request via postman
enter image description here
Here is when sending request using react
enter image description here
From the Axios docs about Request Config data param:
// data is the data to be sent as the request body
// Only applicable for request methods 'PUT', 'POST', 'DELETE , and
'PATCH'
So, data with GET method is not supported.
Can't you use params instead?

ReactJS http-proxy-middleware request header not set properly

TL;DR: How to actually change a request header in http-proxy-middleware?
To get around some CORS errors I set up a local proxy using the http-proxy-middleware module. In addition to setting the mode of my request to "no-cors" I need to change an additional header: "Content-Type". However, this seems to be not working. In fact, I cannot even change the response headers on a redirected (through my proxy) request. For local requests (fetching pages etc) I am able to change the response headers but even then I am unable to change the request headers.
This is my setupProxy.js:
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
app.use((req, res, next) => {
req.header("Content-Type", "application/json");
res.header("Access-Control-Allow-Origin", "*");
next();
});
function onProxyReq(proxyReq, req, res) {
console.log("test 1");
proxyReq.setHeader("Content-Type", "application/json");
req.header("Content-Type", "application/json");
}
app.use(
"/api",
createProxyMiddleware({
target: "https://my-domain.com/",
changeOrigin: true,
onProxyReg: { onProxyReq },
// secure: true,
// on: {
// proxyReq: requestInterceptor(async (buffer, proxyReq, req, res) => {
// console.log("test 2");
// }),
// },
logger: console,
})
);
};
And this is the code that sends the request:
try {
let requestOptions: RequestInit = {
method: "POST",
mode: "no-cors",
headers: {
accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
email: { username },
password: { password },
}),
};
fetch("https://localhost:3000/api/path/to/login/api", requestOptions)
.then(async function (response) {
console.log(response);
if (!response.ok) {
setError("Error code: " + response.status.toString());
}
return response.json();
})
.then(function (response) {
console.log(response);
});
} catch (e) {
console.log(e);
}
I'm getting an error back from the API itself (the CORS avoidance is working):
Content type 'text/plain;charset=UTF-8' not supported
And indeed, when I use the Chrome inspector to look at the request, the request header is set to "text/plain;charset=UTF-8". I tried setting the response header content type to "text/plain" but even that remains untouched. But how can this be after routing the request through my proxy?
EDIT:
Ok so I found out part of the problem. Setting the mode to "no-cors" in my fetch request alters the headers. But this still doesn't explain why my proxy can't edit the request headers. When I remove the "no-cors" mode but copy the headers it produced, the server is giving me error 400 (bad request). This means it is not receiving the same request as before, but this baffles me since I copied all the headers manually.
EDIT2:
Actually, I found out that when I remove mode: "no-cors" and set the "Sec-Fetch-Mode" header to "no-cors" manually, it is still set to "cors" in the actual request!
EDIT3:
I tried sending my request through ReqBin and it works there :)! So at least we know my request is correct.
I found out that changing the "content-type" header in cors mode is simply not allowed. The solution is to first send a preflight request with the options. When this has been accepted, you can send the actual request.
You can send the request through ReqBin, it will take the necessary steps to complete the request succesfully. It will even generate code to reproduce the request for you.
var url = "https://thedomain.com/path/to/api";
var xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
console.log(xhr.status);
console.log(xhr.responseText);
}
};
var data_ = '{"email": "*************", "password": "******"}';
xhr.send(data_);
And this works! :)

Getting request body of mock service worker and react testing library

So i am writing tests for one of my react projects and i just decided to use mock service worker to mock my api calls and i am trying to mock a login endpoint.So i am trying to simulate a login error where i return an error message when the input does not match a particular email. Given the code below;
const server = setupServer(
rest.post("https://testlogin.com/api/v1/login", (req, res, ctx) => {
// the issue is getting the email from the request body something like the code just below
if (req.body["email"] != "test#example.com") {
ctx.status(401);
return res(
ctx.json({
success: false
})
);
}
})
);
How can i do that? Is there a better way to do that?
You should be able to get the req.body.email value given your request sets the Content-Type: application/json header. Without the Content-Type header, neither MSW nor your actual server could know what kind of data you're attempting to send (if anything, it can be a binary!). By providing the correct Content-Type header you form a correct request but also let MSW be sure that req.body should be parsed to an object.
// your-code.js
fetch('https://testlogin.com/api/v1/login', {
method: 'POST',
headers: {
// Adding this header is important so that "req.body"
// is parsed into an object in your request handler.
'Content-Type': 'application/json'
},
body: JSON.stringify({ login: 'admin#site.com' })
})
// your-handlers.js
rest.post('https://testlogin.com/api/v1/login', (req, res, ctx) => {
const { login } = req.body
if (login !== 'test#example.com') {
return res(ctx.status(401), ctx.json({ success: false }))
}
return res(ctx.json({ success: true }))
})
Note how the ctx.status(401) call is inside the res() function call. Calling any ctx[abc] methods outside of res will result in no effect as they rely on being wrapped in res.

How to send a POST request with variables in React?

I am learning how to send a POST request to an API with React.
What I'm trying to achieve right now is sending a POST request to an API.
The API will insert the event with something like this (what is this method called?):
https://api.com/WebService.asmx/insertEvent?event_id=5&desc=<p>HelloWorld</p>&name=testing
The method that I'm currently using as POST is shown at POST method and it returns me with the error unexpected token '<' in json at position 0 and the result that I get when I console.log(JSON.stringify(event)) is something like this:
{"event_id":"5","desc":"<p>HelloWorld</p>","name":"testing"}```
POST method
const response = await fetch('https://api.com/WebService.asmx/insertEvent',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(event)
})
Edit: I've fixed the above error by encoding the HTML that I need to send. This is now my latest POST method, but I'm still facing error 500 for some reason even though it works when I copy and pasted the URL+params from the console.log that has the error shown:
const addBulletin = async (event) => {
console.log(event, '--event')
const url = 'https://api.com/WebService.asmx/insertEvent';
axios.post(url, null, { params: {
title: event.title,
desc: event.desc,
image: event.image,
employee: event.employee,
entity: event.entity,
startDate: event.startDate,
endDate: event.endDate,
createdBy: event.createdBy
}})
.then(response => console.log(response.status))
.catch(err => console.warn(err));
};
Edit: I've tested the API on a vanilla JS project using .ajax with POST, and it works, so I think the API shouldn't be a problem.
var json = $('.insert-form').serialize();
$.ajax({
type: "POST",
url: "https://api.com/WebService.asmx/insertEvent",
data: json,
async: true,
success: function (response) {
alert("Event has been successfully created!");
},
error: function (response) {
console.log(response);
}
});
The API you are sending the request to expects a query parameter (data in the URL).
https://api.com/WebService.asmx/insertEvent?event_id=5&desc=<p>HelloWorld</p>&name=testing
In this request, we are sending 3 query params: event_id, desc, and name.
To send this kind of request from React, you should not use request body. Instead. I advise you to use axios to make it easier. It's a very powerful library, better than using fetch. It should be done this way:
axios.post(`https://api.com/WebService.asmx/insertEvent`, null, { params: {
event_id: eventId,
desc
}})
.then(response => response.status)
.catch(err => console.warn(err));
This may help: How to post query parameters with Axios?

How can I add a CORS header to this Lambda function

Please bare with me as this is my first stack overflow post, but I have minimal backend experience and am really struggling to meet CORS requirements.
I want to use AWS (SES, API Gateway, Lambda) to send form data to our company email account. My function works currently when testing in AWS, but it doesn't work on the client side of my site. From what I've gathered from research so far, my Lambda function needs a CORS header to work. Here is the code:
var aws = require("aws-sdk");
var ses = new aws.SES({ region: "us-east-1" });
exports.handler = async function(payload) {
var params = {
Destination: {
ToAddresses: ['placeholder#place.com'],
},
Message: {
Body: {
Text: {
Data: `\n
${payload.fullName} has tried to contact you. \n
Message: \n
-------------------- \n
${payload.comments} \n
-------------------- \n
Here is the sender's contact information: \n
Name: ${payload.fullName} \n
Email: ${payload.emailAddress} \n
Phone: ${payload.phone} \n
Company: ${payload.companyName}`
},
},
Subject: { Data: payload.subject },
},
Source: 'placeholder#place.com',
};
return ses.sendEmail(params).promise()
};
I'm looking at this code as an example of how to include a CORS header:
exports.handler = async (event) => {
let data = {};
let res = {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*' // replace with hostname of frontend (CloudFront)
},
body: JSON.stringify(data)
};
return res;
};
Can anyone help me to combine these two approaches? I don't understand how to make the SES function into a more traditional response. I am mostly a frontend dev, so I expect that I'm missing something silly. I appreciate any responses though.
If you can change the API Gateway integration type to Lambda Proxy, then this code can help you.
Move the entire code in the handler method to another function say sendEmail
const sendEmail = async function(payload) {
// Your code to crete the `params` omitted for brevity
return ses.sendEmail(params).promise()
};
The handler can call this function and based on the outcome of this function send an appropriate result with the CORS headers
exports.handler = async function(event) {
const payload = JSON.parse(event.body);
const CORS_HEADERS = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*' // Your origin name
};
try {
await sendEmail(payload);
return {
statusCode: 200,
headers: CORS_HEADERS,
body: '{}'
}
} catch(err) {
return {
statusCode: 500, // Can be 4XX or 5XX depending on the error
headers: CORS_HEADERS,
body: `{"err": ${err.messge}}`
}
}
}
For this to work for CORS requests, you also need to ensure the OPTIONS request responds with appropriate headers. You can do so using the AWS console following this documentation. For CloudFormation along with api-gateway V2, this documentation should help. For AWS SAM, this documentation should help (If you are not already using any Serverless development tool, take a look at AWS SAM).
If you don't wish to use the Lambda proxy, then ensure the integration response send the appropriate CORS headers for both the OPTIONS request and the POST request. This can help.

Resources