Telegram Integration Using Firebase - Sending POST Requests

Currently, I am in the process of creating a Firebase cloud function (using Express) that performs the following tasks: - Checking if a user exists in the database. - Sending a message to the Telegram API based on whether the user exists or not.

The problem arises when attempting to execute the function. While Firebase logs successfully display the console.log indicating whether the user exists, the message fails to send to Telegram. The error log states:

[2020-02-15T10:41:34.568Z] @firebase/database: FIREBASE WARNING: Exception was thrown by use callback. Error: Can't set headers after they are sent. at validateHeader (_http_outgoing.js:491:11) at ServerResponse.setHeader (_http_outgoing.js:498:3) at ServerResponse.header (/srv/node_modules/express/lib/response.js:771:10) at ServerResponse.send (/srv/node_modules/express/lib/response.js:170:12) at ServerResponse.json (/srv/node_modules/express/lib/response.js:267:15) at ServerResponse.send (/srv/node_modules/express/lib/response.js:158:21) at firebase.database.ref.child.once.snapshot (/srv/index.js:59:40) at onceCallback (/srv/node_modules/@firebase/database/dist/index.node.cjs.js:4933:51) at /srv/node_modules/@firebase/database/dist/index.node.cjs.js:4549:22 at exceptionGuard (/srv/node_modules/@firebase/database/dist/index.node.cjs.js:698:9)

I would greatly appreciate any assistance provided. Thank you!

 app.post("/", async (req, res) => {

    const isTelegramMessage =
        req.body &&
        req.body.message &&
        req.body.message.chat &&
        req.body.message.chat.id &&
        req.body.message.from &&
        req.body.message.from.first_name &&
        req.body.update_id;
    const user_id = req.body.message.from.id
 firebase.initializeApp(firebaseConfig);
    let myUser;
    const chat_id = req.body.message.chat.id;
    const {
        first_name
    } = req.body.message.from;
    // Check User Exists
    firebase
        .database()
        .ref("/telegramUsers")
        .child(req.body.message.from.id)
        .once("value", snapshot => {
            if (snapshot.exists()) {
                myUser = true;
                console.log("exists!", myUser);
                return res.status(200).send({
                    method: "sendMessage",
                    chat_id,
                    text: `Welcome Back ${first_name}`
                });
            } else {
                myUser = false;
                console.log("does not exist!");
                return res.status(200).send({
                    method: "sendMessage",
                    chat_id,
                    text: `Hello ${first_name}`
                });
            }
        });

    return res.status(200).send({
        status: "not a telegram message"
    });
});

Answer №1

It has been pointed out by others that you are repeating the process of returning and writing a response to the caller twice. When send is used to begin writing the body of the HTTP response, calling status (or even send) after already doing so on res will not work.

In code, this issue would manifest in something similar to the following:

 app.post("/", async (req, res) => {

    const isTelegramMessage =
        req.body &&
        req.body.message &&
        req.body.message.chat &&
        req.body.message.chat.id &&
        req.body.message.from &&
        req.body.message.from.first_name &&
        req.body.update_id;
    const user_id = req.body.message.from.id
    firebase.initializeApp(firebaseConfig);
    let myUser;
    const chat_id = req.body.message.chat.id;
    const {
        first_name
    } = req.body.message.from;
    // Check User Exists
    if (isTelegramMessage) {
      return firebase
        .database()
        .ref("/telegramUsers")
        .child(req.body.message.from.id)
        .once("value")
        .then(snapshot => {
            if (snapshot.exists()) {
                myUser = true;
                console.log("exists!", myUser);
                return res.status(200).send({
                    method: "sendMessage",
                    chat_id,
                    text: `Welcome Back ${first_name}`
                });
            } else {
                myUser = false;
                console.log("does not exist!");
                return res.status(200).send({
                    method: "sendMessage",
                    chat_id,
                    text: `Hello ${first_name}`
                });
            }
          });
    } else {
      return res.status(200).send({
        status: "not a telegram message"
      });
   }
});

The modifications made are:

  • Check for user existence is now only done if isTelegramMessage is true.
  • The result from the database read operation is now returned.
  • Usage of once().then(), ensuring the proper sequence for return res.status().send().... This safeguards against premature termination of Cloud Functions before both database load and response sending are completed.

Although the last two points may not be essential for HTTPS triggered Cloud Functions (since they terminate upon response), their inclusion is recommended to facilitate potential code transfers to other event-triggered Cloud Function types.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Update my React shopping cart with fresh items

I am currently dealing with an issue in my online food ordering system. Specifically, when I click on the add button to order an item, it updates the existing item in the cart instead of appending the new one as the next item. Highlighted below is a cruci ...

Encountering a Type Error in Postman: Unable to destructure

Encountering an issue while using Postman to send a POST request to my backend, resulting in TypeError: Cannot destructure property 'fullName' of 'req.body' as it is undefined The middleware is defined in app.js app.js: import express ...

Is there a way to personalize the appearance of a specific page title in my navigation menu?

I'm currently working on customizing the menu of my WordPress theme to display a different color for the active page name. Although my CSS code works well for all page names except the current one: .navbar-nav li a { font-family: georgia; fo ...

Creating JSON arrays with JavaScript and jQuery

User Information var Users=[{"Id":1,"FirstName":"John"},{"Id":2,"FirstName":"Emily"}] Call Information var CallInfo=[{"Id":1,"PercentageCalls":"22 %","TotalTime":"60:24 minutes","PercentageTime":"0 %","AvgTime":"0:22 minutes"},{"Id":2,"PercentageCa ...

Update submenu panel in jQuery Mobile version 1.4.3 following AJAX request

Hello there, I am currently in the process of developing my first JQuery Mobile website. One of the key features I have implemented is a panel for navigation. Each individual page includes the panel, along with an icon in the header that serves as the butt ...

Differences between Arrow function and regular function when used in Array.map()

While working on some JS challenges, I observed that when using arrow functions, the result is as expected. However, when I try the same code with a regular function, it doesn't work. Can someone please explain the difference or point out if there is ...

Ways to retrieve the selected option from a dropdown list

How can I extract the option value from a dynamically populated Select button in order to retrieve the necessary data from my database? I am unsure of how to obtain the value stored in the $giftName variable. I have attempted to use both jQuery and JavaS ...

Click to load additional data until the list has reached its full length

<ng-container *ngFor="let item of itemList | slice:0:3"> <mat-checkbox>{{item}}</mat-checkbox> </ng-container> <div> <button id="loadMore">Load More</button> </div> I wo ...

Guide on Implementing jQuery UI Autocomplete with Chrome's Speech Input Feature

I have recently discovered a cool feature in Chrome that allows users to dictate into any input field using speech input. Learn more here. It's easy to add this feature in Chrome: <input type="text" x-webkit-speech="x-webkit-speech" /> <!-- ...

Add a npm module without type definitions

I am currently utilizing Typescript version 2.1 and facing an issue with installing an npm package called 'reactable' that lacks typings. When attempting to import the package using import * as Reactable from 'reactable', Typescript di ...

How can you call a function in JavaScript based on a condition?

Is there a way to conditionally truncate text using a function called Truncate only when the offsetHeight of the left div with class demo is greater than the offsetHeight of the right div? If this condition is not met, then simply return the original conte ...

Is there a way to deactivate the <script> tag using CSS specifically for media queries?

When designing a website exclusively for desktop usage, I encountered the issue of it not being viewable on mobile devices. I attempted to address this problem by utilizing the code below: script { display: none; pointer-events: none; } Unfortunat ...

Is there a Clash between JQuery and Bootstrap 4 Popover?

Is there a conflict between JQuery's and Bootstrap 4's popover functions? I am experiencing an issue where the popover does not display when I click on the button element. Below is an example of the code: <link href='https://use.fonta ...

New to Angular: Struggling with complex form validation?

I am just starting to explore Angular and I want to tackle some more advanced input validation. My task involves a table where each row has three text inputs. I need to validate that at least one row has three non-empty input fields. If this criteria is m ...

"Enhance your Vue 3 experience with a stylish Instagram Feed featuring

Struggling to retrieve the most recent Instagram posts from a feed using Vue 3 and Axios due to Instagram's strict-origin-when-cross-origin policy causing constant blocks. All access tokens are properly configured. The Instagram Basic Display API gui ...

Having trouble with Angular 2 and localhost/null error while attempting to make an http.get request?

In my Angular 2 webpage, I am using the OnInit function to execute a method that looks like this (with generic names used): getAllObjects(): Promise<object[]>{ return this.http.get(this.getAllObjectsUrl).toPromise().then(response => response. ...

switching the icon for custom sorting in AngularJS

I managed to implement a custom grid style and sorting icon in AngularJS successfully, except for the toggling of the sorting icon. Here is my HTML code for headers: <div ng-app="myApp"> <div ng-controller="TableCtrl"> <table ...

Is there a way to use Ajax to analyze and contrast information from two separate web links?

I am looking to compare and display the genre_ids from the first link and the id from the second link. Example: genre_ids: [ 18, 878, ] { id: 18, name: "Drama", }, { id: 878, name: "Science Fiction", } Result: Drama, Science Fiction $(document).ready( ...

Enabling Cross-Origin Resource Sharing (CORS) with Javascript on the client side during

Currently, I am attempting to incorporate another website's login verification system into my own site. Although the code below is successfully retrieving the correct response ID, I am encountering CORS errors preventing the completion of the login pr ...

What is the best way to dynamically change the content of a div based on user selection?

When a user selects an option in the HTML, I want to display another div set to Block. I tried putting the OpenAskuser() function in a button, but it didn't work either. It would be ideal if we could achieve this without a button. Just have the displ ...