Error: Can't set headers after they are sent node.js - javascript

hi guys im fairly new to node.js and I was wonder if I am making a call twice that I am unaware of. I am getting a Error: Can't set headers after they are sent.
export const hearingReminder = functions.https.onRequest((request, response) => {
console.log(request.body)
const payload = {
notification: {
title: 'Upcoming Hearing',
body: 'You have a hearing in one hour.',
}
};
const fcm = request.body.fcm
console.log(request.body.fcm)
try {
response.status(200).send('Task Completed');
return admin.messaging().sendToDevice(fcm, payload);
} catch (error) {
return response.status(error.code).send(error.message);
}

Your code is attempting to send a response twice, under the condition that admin.messaging().sendToDevice generates an error. Instead of sending the 200 response before the call, only send it after the call. Sending the response should always be the very last thing performed in your function.
Your code should be more like this:
admin.messaging().sendToDevice(fcm, payload)
.then(() => {
response.status(200).send('Task Completed');
})
.catch(error => {
response.status(error.code).send(error.message);
})
Note that you don't need to return anything for HTTP type functions. You just need to make sure to handle all the promises, and only send the response after all the promises are resolved.

Related

nodejs app crash on openai dall-e 2 api rejected request

I'm surely dumb, but I'm not able to figure out how to handle openai api rejected requests
( for the context, dall-e 2 is an image generator )
when user tries to generate forbidden images, my nodejs app just exits
async function start(arg) {
try{
// generate image
const response = openai.createImage({
prompt: arg,
n: 1,
size: "1024x1024",
});
// on success response
response.then(res =>{
console.log("ok");
})
response.catch(err =>{
console.log(err);
});
} catch(e){
console.log(e);
}
}
it gives me something like that on the exit :
data: {
error: {
code: null,
message: 'Your request was rejected as a result of our safety system. Your prompt may contain text that is not allowed by our safety system.',
param: null,
type: 'invalid_request_error'
}
}
tried using response.catch and try catch without success, the app just exits everytime
I at least want to ignore this error in the first place
in a second hand, I would like to console.log the given message (data.error.message)
I don't know what to do to by honest, don't even understand why try catch isn't working
With the details given, my guess would be that the Promise returned by getImages is being rejected. You could debug this a bit by adding some additional logs into your .catch callback and catch statement.
How to do this really depends on what you're trying to do with this api, the code as it's currently written would log something and exit no matter what happens.
There's a couple ways to handle this
Use your .catch to handle the error. Utilizing promise chainability you can get something like this
openai.createImage({
prompt: arg,
n: 1,
size: "1024x1024",
user: msg.author.id,
})
.catch((e) => {
if (e.data.error.message.includes('safety system')) {
return 'something'
}
console.error(e)
})
If you need the response object, the asnwer might be different. Looks like the openai package is built on axios and you can pass axios options into it. See https://axios-http.com/docs/handling_errors and the Request Options section of https://npmjs.com/package/openai
EDIT
I found my solution thanks to #JacksonChristoffersen
Basically I was getting http status 400
I just added request options from axios to validate http status smaller than 500
Here's the solution:
async function start(arg) {
try{
// generate image
const response = openai.createImage({
prompt: arg,
n: 1,
size: "1024x1024",
},{
validateStatus: function (status) {
return status < 500; // Resolve only if the status code is less than 500
}
});
// on success response
response.then(res =>{
console.log("ok");
})
response.catch(err =>{
console.log(err);
});
} catch(e){
console.log(e);
}
}

NEXTJS - fetching data from the server

I want to fetch data from the nextjs server on the front end, however the code after fetch() doesn't work in the onSubmit() function.
here is the /test page
pages/test
const onSubmit = (data) => {
console.log("________");
users.map(async (user, index) => {
if (data.email === user.email) {
if (data.password === user.password) {
console.log("hi");
const data = await fetch("http://localhost:3000/api/test");
// after the fetch, this code does not run
console.log("back-end is: ", data);
}
}
});
};
and here is my code in /api/test
export default async function student_method(req, res) {
return console.log("get in server");
}
so please what is the problem??
i'm try to get the data inside the database
so we need to use fetch() method but fetch() work succesfully but code after fetch() does not work
I think the issue is using the return statement on the server side. NextJS provides helper methods in the res object you receive in your server-side function.
Try something like this:
res.status(200).send("get in server");
For details, see here: API Routes: Response Helpers
const data = await fetch("http://localhost:3000/api/test");
The problem is that line. There you waiting a Promise resolve, but if you see you api/test you only return a log.
Please try returning a Promise.
The code is not working now because you're waiting for the server response but you aren't sending anything from the server.
You should send response to the client like this:
export default async function student_method(req, res) {
/* status code 200 or any other status codes */
res.status(200).send("get in server");
}

Error while trying to get realtime data from firestore database code: 'ERR_HTTP_HEADERS_SENT'

i am trying to build an app and i am very new to all this. So I've built a very simple function to get data from firestore and it works fine from a moment. This is the code:
async getData(req, res) {
const dataRef = db.collection(`${req.body.banco}`)
let result = []
dataRef.onSnapshot(docSnapshot => {
docSnapshot.forEach(doc => {
const data = doc.data()
result.push(data)
})
console.log(result)
return res.status(200).send(result)
}, (error) => {
console.log(`Erro encontrado: ${error}`)
})
}
My problem is that when I try to update any field from the document. It gets updated but I end up receiving this error:
node:_http_outgoing:576
throw new ERR_HTTP_HEADERS_SENT('set');
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:372:5)
at ServerResponse.setHeader (node:_http_outgoing:576:11)
at ServerResponse.header (C:\Users\paulo\Desktop\sirius-back\functions\node_modules\express\lib\response.js:794:10)
at ServerResponse.send (C:\Users\paulo\Desktop\sirius-back\functions\node_modules\express\lib\response.js:174:12)
at ServerResponse.json (C:\Users\paulo\Desktop\sirius-back\functions\node_modules\express\lib\response.js:278:15)
at ServerResponse.send (C:\Users\paulo\Desktop\sirius-back\functions\node_modules\express\lib\response.js:162:21)
at C:\Users\paulo\Desktop\sirius-back\functions\src\controller\createDocs.js:70:40
at QueryWatch.onNext (C:\Users\paulo\Desktop\sirius-back\functions\node_modules\#google-cloud\firestore\build\src\reference.js:1914:13)
at QueryWatch.pushSnapshot (C:\Users\paulo\Desktop\sirius-back\functions\node_modules\#google-cloud\firestore\build\src\watch.js:469:18)
at QueryWatch.onData (C:\Users\paulo\Desktop\sirius-back\functions\node_modules\#google-cloud\firestore\build\src\watch.js:353:26) {
code: 'ERR_HTTP_HEADERS_SENT'
}
the app crashes and i have to start it over.
What is the reason of this? How can i get realtime updates from firestore databse after I update something from?
In Express you handle each requests by sending a single response to it. Since res a a response object, you can only send a response to the caller once. But since you're using onSnapshot, your code gets called for every change to the data too.
So initially, you load the data and send a response to the caller and all is 👍
But then when an update is made to the database, your code executes again and tries to send another response to the caller - and this is when you get an error.
The solution is to read the data only one with something like:
async getData(req, res) {
const dataRef = db.collection(`${req.body.banco}`)
let result = []
dataRef.get().then((docSnapshot) => {
docSnapshot.forEach((doc) => {
const data = doc.data()
result.push(data)
})
console.log(result)
return res.status(200).send(result)
}, (error) => {
console.log(`Erro encontrado: ${error}`)
})
}
Or a bit simplified:
async getData(req, res) {
const dataRef = db.collection(`${req.body.banco}`)
dataRef.get().then((docSnapshot) => {
const result = docSnapshot.docs.map((doc) => doc.data());
return res.status(200).send(result)
}, (error) => {
console.log(`Erro encontrado: ${error}`)
})
}
Once you've called res.send(...) the request is complete and the client stops listening. Sending further updates to a response is not possible with an Express request/response model like you're using.
Also see:
How to send multiple responses while computing in Express.js?
Sending multiple responses(res.json) with the same response object in Express.js
and more from searching for how to send multiple responses for a single request in express
You'll need to choose an infrastructure that allows a client to keep listening. Heads up: building something like that is quite involved, and you're likely better off if you use the client-side Firestore SDK to implement such realtime listeners

How can you use axios interceptors?

I have seen axios documentation, but all it says is
// Add a request interceptor
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Do something with response data
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
Also many tutorials only show this code but I am confused what it is used for, can someone please give me simple example to follow.
To talk in simple terms, it is more of a checkpoint for every HTTP action. Every API call that has been made, is passed through this interceptor.
So, why two interceptors?
An API call is made up of two halves, a request, and a response. Since it behaves like a checkpoint, the request and the response have separate interceptors.
Some request interceptor use cases -
Assume you want to check before making a request if your credentials are valid. So, instead of actually making an API call, you can check at the interceptor level that your credentials are valid.
Assume you need to attach a token to every request made, instead of duplicating the token addition logic at every Axios call, you can make an interceptor that attaches a token on every request that is made.
Some response interceptor use cases -
Assume you got a response, and judging by the API responses you want to deduce that the user is logged in. So, in the response interceptor, you can initialize a class that handles the user logged in state and update it accordingly on the response object you received.
Assume you have requested some API with valid API credentials, but you do not have the valid role to access the data. So, you can trigger an alert from the response interceptor saying that the user is not allowed. This way you'll be saved from the unauthorized API error handling that you would have to perform on every Axios request that you made.
Here are some code examples
The request interceptor
One can print the configuration object of axios (if need be) by doing (in this case, by checking the environment variable):
const DEBUG = process.env.NODE_ENV === "development";
axios.interceptors.request.use((config) => {
/** In dev, intercepts request and logs it into console for dev */
if (DEBUG) { console.info("✉️ ", config); }
return config;
}, (error) => {
if (DEBUG) { console.error("✉️ ", error); }
return Promise.reject(error);
});
If one wants to check what headers are being passed/add any more generic headers, it is available in the config.headers object. For example:
axios.interceptors.request.use((config) => {
config.headers.genericKey = "someGenericValue";
return config;
}, (error) => {
return Promise.reject(error);
});
In case it's a GET request, the query parameters being sent can be found in config.params object.
The response interceptor
You can even optionally parse the API response at the interceptor level and pass the parsed response down instead of the original response. It might save you the time of writing the parsing logic again and again in case the API is used in the same way in multiple places. One way to do that is by passing an extra parameter in the api-request and use the same parameter in the response interceptor to perform your action. For example:
//Assume we pass an extra parameter "parse: true"
axios.get("/city-list", { parse: true });
Once, in the response interceptor, we can use it like:
axios.interceptors.response.use((response) => {
if (response.config.parse) {
//perform the manipulation here and change the response object
}
return response;
}, (error) => {
return Promise.reject(error.message);
});
So, in this case, whenever there is a parse object in response.config, the manipulation is done, for the rest of the cases, it'll work as-is.
You can even view the arriving HTTP codes and then make the decision. For example:
axios.interceptors.response.use((response) => {
if(response.status === 401) {
alert("You are not authorized");
}
return response;
}, (error) => {
if (error.response && error.response.data) {
return Promise.reject(error.response.data);
}
return Promise.reject(error.message);
});
You can use this code for example, if you want to catch the time that takes from the moment that the request was sent until the moment you received the response:
const axios = require("axios");
(async () => {
axios.interceptors.request.use(
function (req) {
req.time = { startTime: new Date() };
return req;
},
(err) => {
return Promise.reject(err);
}
);
axios.interceptors.response.use(
function (res) {
res.config.time.endTime = new Date();
res.duration =
res.config.time.endTime - res.config.time.startTime;
return res;
},
(err) => {
return Promise.reject(err);
}
);
axios
.get("http://localhost:3000")
.then((res) => {
console.log(res.duration)
})
.catch((err) => {
console.log(err);
});
})();
It is like a middle-ware, basically it is added on any request (be it GET, POST, PUT, DELETE) or on any response (the response you get from the server).
It is often used for cases where authorisation is involved.
Have a look at this: Axios interceptors and asynchronous login
Here is another article about this, with a different example: https://medium.com/#danielalvidrez/handling-error-responses-with-grace-b6fd3c5886f0
So the gist of one of the examples is that you could use interceptor to detect if your authorisation token is expired ( if you get 403 for example ) and to redirect the page.
I will give you more practical use-case which I used in my real world projects. I usually use, request interceptor for token related staff (accessToken, refreshToken), e.g., whether token is not expired, if so, then update it with refreshToken and hold all other calls until it resolves. But what I like most is axios response interceptors where you can put your apps global error handling logic like below:
httpClient.interceptors.response.use(
(response: AxiosResponse) => {
// Any status code that lie within the range of 2xx cause this function to trigger
return response.data;
},
(err: AxiosError) => {
// Any status codes that falls outside the range of 2xx cause this function to trigger
const status = err.response?.status || 500;
// we can handle global errors here
switch (status) {
// authentication (token related issues)
case 401: {
return Promise.reject(new APIError(err.message, 409));
}
// forbidden (permission related issues)
case 403: {
return Promise.reject(new APIError(err.message, 409));
}
// bad request
case 400: {
return Promise.reject(new APIError(err.message, 400));
}
// not found
case 404: {
return Promise.reject(new APIError(err.message, 404));
}
// conflict
case 409: {
return Promise.reject(new APIError(err.message, 409));
}
// unprocessable
case 422: {
return Promise.reject(new APIError(err.message, 422));
}
// generic api error (server related) unexpected
default: {
return Promise.reject(new APIError(err.message, 500));
}
}
}
);
How about this. You create a new Axios instance and attach an interceptor to it. Then you can use that interceptor anywhere in your app
export const axiosAuth = axios.create()
//we intercept every requests
axiosAuth.interceptors.request.use(async function(config){
//anything you want to attach to the requests such as token
return config;
}, error => {
return Promise.reject(error)
})
//we intercept every response
axiosAuth.interceptors.request.use(async function(config){
return config;
}, error => {
//check for authentication or anything like that
return Promise.reject(error)
})
Then you use axiosAuth the same way you use axios
This is the way I used to do in my project. The code snippet refers how to use access and refresh token in the axios interceptors and will help to implements refresh token functionalities.
const API_URL =
process.env.NODE_ENV === 'development'
? 'http://localhost:8080/admin/api'
: '/admin-app/admin/api';
const Service = axios.create({
baseURL: API_URL,
headers: {
Accept: 'application/json',
},
});
Service.interceptors.request.use(
config => {
const accessToken = localStorage.getItem('accessToken');
if (accessToken) {
config.headers.common = { Authorization: `Bearer ${accessToken}` };
}
return config;
},
error => {
Promise.reject(error.response || error.message);
}
);
Service.interceptors.response.use(
response => {
return response;
},
error => {
let originalRequest = error.config;
let refreshToken = localStorage.getItem('refreshToken');
const username = EmailDecoder(); // decode email from jwt token subject
if (
refreshToken &&
error.response.status === 403 &&
!originalRequest._retry &&
username
) {
originalRequest._retry = true;
return axios
.post(`${API_URL}/authentication/refresh`, {
refreshToken: refreshToken,
username,
})
.then(res => {
if (res.status === 200) {
localStorage.setItem(
'accessToken',
res.data.accessToken
);
localStorage.setItem(
'refreshToken',
res.data.refreshToken
);
originalRequest.headers[
'Authorization'
] = `Bearer ${res.data.accessToken}`;
return axios(originalRequest);
}
})
.catch(() => {
localStorage.clear();
location.reload();
});
}
return Promise.reject(error.response || error.message);
}
);
export default Service;
I have implemented in the following way
httpConfig.js
import axios from 'axios'
import { baseURL } from '../utils/config'
import { SetupInterceptors } from './SetupInterceptors'
const http = axios.create({
baseURL: baseURL
})
SetupInterceptors(http)
export default http
SetupInterceptors.js
import { baseURL } from '../utils/config'
export const SetupInterceptors = http => {
http.interceptors.request.use(
config => {
config.headers['token'] = `${localStorage.getItem('token')}`
config.headers['content-type'] = 'application/json'
return config
},
error => {
return Promise.reject(error)
}
)
http.interceptors.response.use(function(response) {
return response
}, function (error) {
const status = error?.response?.status || 0
const resBaseURL = error?.response?.config?.baseURL
if (resBaseURL === baseURL && status === 401) {
if (localStorage.getItem('token')) {
localStorage.clear()
window.location.assign('/')
return Promise.reject(error)
} else {
return Promise.reject(error)
}
}
return Promise.reject(error)
})
}
export default SetupInterceptors
Reference : link

Feathersjs: how to send a response and after that trigger a function?

I had some code working fine for a REST endpoint in which a message was:
created in the database
stepA was processed
when stepA was ok, the response message was returned
stepB was processed.
This was the code:
// POST single message
app.post('/message', (req, res) => {
const url = req.body.properties.url
const image = req.body.properties.image
const extraField = req.body.properties.extraField
db.message.create({
url: url,
image: image,
})
.then(() => myProcess(extraField, 'stepA'))
.then(newMessage => res.json(newMessage))
.then(() => myProcess(extraField, 'stepB'))
})
Now I am trying to have the same using feathersjs, but I do not know how to do 2, 3, 4 exactly.
I have now an AFTER hook for the create method of the message service:
module.exports = function (options = {}) { // eslint-disable-line no-unused-vars
return function processNewMessage (hook) {
const { extraField } = hook.data.properties
Promise.resolve(myProcess(extraField, 'stepA'))
.then( <<NO-IDEA>> ) // Send RESPONSE!!
.then(() => myProcess(extraField, 'stepB'))
return Promise.resolve(hook);
};
};
So my question boils down to: How can I send the response and subsequently trigger 'myProcess stepB' using feathersjs?
Althoug this is 'legacy', I think it might still be relevant.
It is answered in the FAQ of feathersjs!
How to do processing after sending the response to the user:
It depends on the promise that you return in your hook. Here's an example of a hook that sends an email, but doesn't wait for a success message.
function (hook) {
// Send an email by calling to the email service.
hook.app.service('emails').create({
to: 'user#email.com',
body: 'You are so great!'
});
// Send a message to some logging service.
hook.app.service('logging').create(hook.data);
// Return a resolved promise to immediately move to the next hook
// and not wait for the two previous promises to resolve.
return Promise.resolve(hook);
}

Categories

Resources