Skip to content

Latest commit

 

History

History
236 lines (172 loc) · 8.55 KB

README.md

File metadata and controls

236 lines (172 loc) · 8.55 KB

cdg_api

Crates.io MIT License

A simple Rust library to interact with the US Congress API.

Installation

Add cdg_api to your Cargo.toml:

[dependencies]
cdg_api = "1.3.6"

Or use cargo to add the dependency:

cargo add cdg_api

If you don't want to pull in reqwest as a dependency, you can disable the requests feature by just disabling the default features:

[dependencies]
cdg_api = { version = "1.3.6", default-features = false }

or

cargo add cdg_api --no-default-features

Getting Started

Setting Up Your API Key

Obtain an API key from the US Congress API. Provide it to the CongressApiClient either via an environment variable or direct initialization:

  1. Environment Variable:

    export CDG_API_KEY="your_api_key_here"
  2. Direct Initialization:

    use cdg_api::CongressApiClient;
    
    let client = CongressApiClient::new(Some("your_api_key_here".to_string())).unwrap();

Note: Using environment variables is recommended to avoid hardcoding sensitive information.

Using CongressApiClient

[CongressApiClient] allows you to interact with various API endpoints. Below are examples demonstrating how to fetch different types of data, including the fetch-all Endpoints::Generic variant.

For more detailed information, see the documentation, the examples directory, and the US Congress API documentation.

Example 1: Fetching Members

Fetch a list of current members of Congress and display their names, party affiliations, and states.

use cdg_api::CongressApiClient;
use cdg_api::endpoints::{Endpoints, NewEndpoint};
use cdg_api::param_models::MemberListParams;
use cdg_api::cdg_types::FormatType;
use cdg_api::response_models::MembersResponse;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = CongressApiClient::new(None)?; // Use API key from environment

    // Create the endpoint and define parameters
    let endpoint = Endpoints::new_member_list(
        MemberListParams::default()
            .format(FormatType::Json)
            .limit(10)
            .current_member(true)
    );

    // Fetch the data
    let response: MembersResponse = client.fetch(endpoint)?;

    // Process the response
    for member in response.members {
        println!("{}, {}, {}\n", 
            member.name.unwrap_or_default(),
            member.state.unwrap_or_default(),
            member.party_name.unwrap_or_default()
        );
    }

    Ok(())
}

Example 2: Using GenericResponse with parse_response

Fetch detailed information about a specific bill using GenericResponse and parse it into a specific response model.

use cdg_api::CongressApiClient;
use cdg_api::endpoints::{Endpoints, NewEndpoint};
use cdg_api::param_models::BillDetailsParams;
use cdg_api::cdg_types::{BillType, FormatType};
use cdg_api::response_models::{BillDetailsResponse, GenericResponse, serialize_response, parse_response};

use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let client = CongressApiClient::new(None)?; // Use API key from environment

    // Define parameters for bill details
    let params = BillDetailsParams::default()
        .format(FormatType::Json);

    // Specify the bill to fetch (e.g., H.R. 1234 from the 118th Congress)
    let endpoint = Endpoints::new_bill_details(118, BillType::Hr, 148, params);

    // Fetch the data as GenericResponse
    let response: GenericResponse = client.fetch(endpoint)?;

    // Parse the response as BillDetailsResponse
    let bill_details: BillDetailsResponse = match parse_response(&response) {
        Ok(bill_details) => bill_details,
        Err(e) => {
            // If parsing fails to a specific primary response fails, the GenericResponse can be serialized
            // to see the response structure. This can help in debugging and creating a specific response model.
            // The argument `true` pretty prints the response, `false` prints the raw JSON.
            println!("Failed to parse response: {}", e);
            println!("Response:\n\n{}", serialize_response(&response, true)?);
            return Ok(());
        }
    };
    let bill = bill_details.bill;

    println!("Bill: {}", bill.number.unwrap_or_default());
    println!("Title: {}", bill.title.unwrap_or_default());
    println!("Summary: {:#?}", bill.summaries.unwrap_or_default());

    Ok(())
}

Example 3: Using Endpoints::Generic for Custom Endpoints

When working with custom or unknown endpoints, you can use Endpoints::Generic to specify the endpoint string such as daily-congressional-record and GenericParams to define query parameters. The response can be fetched as GenericResponse. The Endpoint created can then call parse_response to parse the response into a specific response model. If parsing fails, the GenericResponse can be serialized to see the response structure.

This is essentially the Endpoints equivalent of the GenericResponse example above. One for requests and the other for responses.

use cdg_api::CongressApiClient;
use cdg_api::endpoints::{Endpoints, NewEndpoint};
use cdg_api::response_models::{DailyCongressionalRecordResponse, GenericResponse, serialize_response, parse_response};
use cdg_api::param_models::GenericParams;
use cdg_api::cdg_types::*;

use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let client = CongressApiClient::new(None)?; // Use API key from environment

    // Manually specify the endpoint string and parameters
    let endpoint = Endpoints::new_generic(
      "daily-congressional-record".to_string(),
      GenericParams::default().format(FormatType::Json)
    );

    // Fetch the data as GenericResponse. Theoretically, you could use any endpoint string
    // and parameters here, but the response structure may not be known, we parse it into the
    // suspected response model after fetching. We do this by calling `parse_response`, it 
    // will return a specific response model if the structure is known, else it will return
    // the GenericResponse. This ensures that the response is always parsed, rather than throwing
    // an error if the structure is unknown or unexpected during the fetch.
    let response: GenericResponse = client.fetch(endpoint)?;

    // Parse the response into DailyCongressionalRecordResponse
    match parse_response::<DailyCongressionalRecordResponse, GenericResponse>(&response) {
        Ok(daily_record) => {
            let record = daily_record.daily_congressional_record;
            for issue in record {
                println!("Issue Number: {}", issue.issue_number.unwrap_or_default());
                println!("Volume Number: {}", issue.volume_number.unwrap_or_default());
                println!("Issue Date: {}", issue.issue_date.unwrap_or_default());
                println!("Congress: {}", issue.congress.unwrap_or_default());
                println!("Session Number: {}", issue.session_number.unwrap_or_default());
                println!("URL: {}", issue.url.unwrap_or_default());
                println!("Sections:");
                if let Some(full) = issue.full_issue {
                    println!("Full Record: {:#?}", full);
                }
                println!("----------------------------");
            }
        },
        Err(e) => {
            println!("Failed to parse response: {}", e);
            println!("Response:\n\n{}", serialize_response(&response, true)?);
        }
    }

    Ok(())
}

Related Projects

  • loc_api : A Rust library for interacting with the Library of Congress API. Less polished than cdg_api, barebones interface, but functional.

License

This project is licensed under the terms of the MIT license.

Repository

https://github.com/t-fbd/cdg_api

Acknowledgements

The data is sourced from the U.S. Congress API. See their repository for more information: LibraryOfCongress/api.congress.gov.

Contact

For questions or feedback, please contact me on github.

If you find this project helpful, consider donating PayPal.