Pull Congressional Data via SMS with the Congress API and JavaScript

October 31, 2022
Written by
Reviewed by
Shawn Stern
Contributor
Opinions expressed by Twilio contributors are their own

blog header

Congress recently came out with an official API so the public can "view, retrieve, and re-use machine-readable data from collections available on Congress.gov!" Read on to learn how to read congressional data using the Congress API, Twilio Functions, and the Twilio Serverless Toolkit.

Text "bill", "amendment", or "summaries" to +12029337044 to receive data about a random bill or amendment!

bill example

Prerequisites

  1. A Twilio account - sign up for a free one here
  2. A Twilio phone number with SMS capabilities - configure one here
  3. A Congress.gov API Key – get one here
  4. Postman (you could alternatively make cURL requests from the command line)
  5. Node.js installed - download it here

Make a congress.gov Request  

You can look over the different Congress API endpoints offered here. To get someone's profile information, the URL would look like https://api.congress.gov/v3/bill/117/s/4693/summaries where 117 is the Congress number, "s" is the type of bill, and "4693" is the bill number. Open Postman and paste that URL into the URL bar.

Add your API Key under Params: the key is api_key and the value is your Congress API Key.

Click Send to hit it with a GET request to see the following data returned:

Postman example with API key blocked out

Again, you can see more Congress API endpoints here you can play around with!

Get Started with the Twilio Serverless Toolkit

The Serverless Toolkit is CLI tooling that helps you develop locally and deploy to Twilio Functions & Assets. The best way to work with the Serverless Toolkit is through the Twilio CLI. If you don't have the Twilio CLI installed yet, run the following commands on the command line to install it and the Serverless Toolkit:

npm install twilio-cli -g
twilio login
twilio plugins:install @twilio-labs/plugin-serverless

Afterwards, create your new project and install our lone requirement undici to make HTTP requests in Node.js by running:

twilio serverless:init congress-api-sms –template=blank
cd congress-api-sms
npm install -s undici

The Functions and Assets team recommends using undici with your Functions.

Set an Environment Variable with Twilio Functions and Assets

Open up your .env file for your Functions project in your root directory and add the following line:

CONGRESS_API_KEY=YOUR-CONGRESS-API-KEY

Now you can access this API Key if you'd like to do so in your code with context.CONGRESS_API_KEY.

Make a Twilio Function with JavaScript

Make a new file in the /functions directory called congress.js containing the following code:

exports.handler = async (context, event, callback) => {
  const { request } = await import('undici');
  const inbMsg = event.Body.toLowerCase().trim();
  const twiml = new Twilio.twiml.MessagingResponse();
  if(inbMsg.includes("bill")) {
    const {
      body
    } = await request(`https://api.congress.gov/v3/bill?api_key=${context.CONGRESS_API_KEY}`);
    const data = await body.json();
    const billsLength = data.bills.length;
    const randNum = Math.floor(Math.random() * (billsLength - 1)) + 1;
    const bill = data.bills[randNum];
    const { latestAction, title, type, number, originChamber } = bill;
    
    const billMap = {
        HR: "house bill",
        S: "senate bill",
        HJRES: "house joint resolution",
        SJRES: "senate joint resolution",
        HCONRES: "house concurrent resolution",
        SCONRES: "senate concurrent resolution",
        HRES: "house simple resolution",
        SRES: "senate simple resolution"
    };
    twiml.message(`Bill: ${title}.\nType: ${billMap[type]}\nAssigned bill or resolution number:   ${number}\nIt originated in the ${originChamber} but the latest action was ${latestAction.text} on ${latestAction.actionDate}`);
  }
  else if(inbMsg.includes("amendment")) {
    const {
      body
    } = await request(`https://api.congress.gov/v3/amendment?api_key=${context.CONGRESS_API_KEY}`);
    const data = await body.json();
    const amendmentLength = data.amendments.length;
    const randNum = Math.floor(Math.random() * (amendmentLength - 1)) + 1;
    const amendment = data.amendments[randNum];
    const { latestAction, purpose, congress, number } = amendment;
    twiml.message(`Amendment purpose: ${purpose}\nAssigned amendment or resolution number:${number}\n Latest action was on ${latestAction.actionDate} to ${latestAction.text}.\n Congress: ${congress}.`);
  }
  else if(inbMsg.includes("summaries")) {
    const CURRENT_CONGRESS = 117;
    const {
      body
    } = await request(`https://api.congress.gov/v3/summaries/${CURRENT_CONGRESS}?api_key=${context.CONGRESS_API_KEY}`);
    const data = await body.json();
    const sumLength = data.summaries.length;
    const randNum = Math.floor(Math.random() * (sumLength - 1)) + 1;
    const summaries = data.summaries[randNum];
    const { bill, currentChamber, text, actionDate, actionDesc } = summaries;
    const regexToStripHtmlTags = /<(.|\n)*?>/g;
    const textWithoutHtmlTags = text.replace(regexToStripHtmlTags, '');
    const msg = `Summary title: ${bill.title}.\nStarted in: ${bill.originChamber} on ${actionDate}, currently in the ${currentChamber} chamber in Congress ${bill.congress} and it was ${actionDesc}\n${textWithoutHtmlTags}`; 
    twiml.message(msg);
  }
  else {
    twiml.message(`Send "bill", "amendment", or "summaries"`);
  }
  callback(null, twiml);
};

This code imports undici, makes a Twilio Messaging Response object, creates a variable inbMsg from the inbound text message users will text in and checks if that message input contains bill, amendment, or summaries (three endpoints of the Congress API). The code then generates a random number based on the total amount of items returned from the Congress API to select a random Bill or Amendment, parses the responses from that given endpoint (as we saw using Postman above) into variables such as the type of Amendment or Bill, the most recent date some action was taken, and more!

If someone does not send a message containing "bill", "summaries", or "amendment" (the three topics they can learn about), we return a message saying so. Else, we parse the Congress object returned for information such as the latest action taken on a bill, type of bill, purpose of the given random amendment, origin chamber of a bill, and more. We return a text message containing that data!

You can view the complete app on GitHub here.

Configure the Function with a Twilio Phone Number

To open up our app to the web with a public-facing URL, run twilio serverless:deploy from the congress-api-sms root directory. You should see this at the bottom of your terminal:

twilio functions url deployed

Grab the Function URL corresponding to your app (the one that ends with  /congress) and configure a Twilio phone number with it as shown below: select the Twilio number you just purchased in your Twilio phone numbers console and scroll down to the Messaging section. Paste the link in the text field for A MESSAGE COMES IN webhook making sure that it's set to HTTP POST. When you click Save it should look like this!

messaging section of phone number in console

The Service is the Serverless project name, environment provides no other options, and Function Path is the file name. Now take out your phone and text "bill" or "amendment" or "summaries" to your Twilio number.

text example for amendment and bill
kimmy schmidt gif: "being in congress must be fun!"

Twilio's Serverless Toolkit makes it possible to deploy web apps quickly, and Functions & Assets seamlessly handles servers for you. Let me know online what you're building with Serverless and don't forget to vote this November!