25 releases (8 stable)
1.3.5 | Nov 4, 2024 |
---|---|
0.9.5 | Nov 1, 2024 |
#154 in Data structures
410KB
7K
SLoC
cdg_api
A simple Rust library to interact with the US Congress API.
cdg_api
provides a Rust interface for interacting with the US Congress API. It simplifies constructing API endpoints, building URLs with parameters, and retrieving legislative data. Whether fetching information about bills, members, amendments, or laws, cdg_api
offers a streamlined and type-safe approach to accessing this data.
The library is a work in progress but is very much functional. It is designed to be modular, extensible, and easy to use. The CongressApiClient
struct serves as the central component for making requests, handling responses, and managing API keys. The library includes specific models for various API responses, such as bills, members, nominations, and treaties, as well as a versatile GenericResponse
for handling unknown response structures.
Please, if you find any issues, particularly with the API responses or models as I find it tedious to test all of them, feel free to open an issue or submit a pull request.
Table of Contents
- Overview
- Features
- Installation
- Getting Started
- Using
CongressApiClient
- Other Projects
- License
- Repository
Quick Info
Around 100+ endpoints models available for interacting with the US Congress API, as well as the ability to create custom endpoints using Endpoints::Generic
.
Around 150+ response models available for parsing API responses, including specific models for bills, members, nominations, treaties, and more.
-
Modules:
- endpoints: Models representing available API endpoints, including
Endpoints::Generic
for custom endpoints. - url_builders: Utility functions for constructing API URLs with query parameters.
- param_models: Models and enums for different query parameters.
- param_chains: Build chains for every param_model and the macro that constructs them.
- response_models: Models for API responses, including specific models and the versatile
GenericResponse
. - cdg_client:
CongressApiClient
struct for interacting with the API. - cdg_types: Enums and structs and implementations for various custom types used in the API.
- ser_deser_cdg: Response handling functions. See below.
- endpoints: Models representing available API endpoints, including
-
Api Client:
- CongressApiClient: Centralized client managing API keys, constructing URLs, making requests, and deserializing responses.
-
Generic Response Handling:
- GenericResponse: A catch-all response model for endpoints without a specific response type or when the response model is unknown.
-
Response Handling
- parse_response: A method to parse
GenericResponse
into a specific response model when the structure is known. - serialize_response: A method to serialize
GenericResponse
into a JSON string for debugging or creating a specific response model, a good fallback when parsing fails.
- parse_response: A method to parse
-
Modules by Feature Flags:
- Feature Flag:
request_handlers
(enabled by default):- request_handlers: Functions for making HTTP requests and handling responses, parts of which are used by
CongressApiClient
.
- request_handlers: Functions for making HTTP requests and handling responses, parts of which are used by
- Feature Flag:
Installation
Add cdg_api
to your Cargo.toml
:
[dependencies]
cdg_api = "*"
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 = "*", 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:
-
Environment Variable:
export CDG_API_KEY="your_api_key_here"
-
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 new Endpoints::Generic
variant.
Example 1: Fetching Members
Fetch a list of current members of Congress and display their names, party affiliations, and states.
ps. Instead of using the standard unwrap
methods, you can use cdg_api::unwrap_option()
], cdg_api::unwrap_option_string()
, or cdg_api::unwrap_option_u32()
in order to quickly unwrap the Option
values and provide a default value if the value is None
. Pretty much the same as unwrap_or_default()
.
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
let endpoint = Endpoints::new_generic(
"daily-congressional-record".to_string(),
GenericParams::default().format(FormatType::Json)
);
// Fetch the data as GenericResponse
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(())
}
Other Projects
-
loc_api
: A Rust library for interacting with the Library of Congress API. -
congress_rollcalls
: Github repository holding mass data of roll call votes in the US Congress.
License
This project is licensed under the terms of the MIT license.
Repository
https://github.com/t-fbd/cdg_api
The data is sourced from the U.S. Congress API.
Contact
For questions or feedback, please contact me on github or email me here.
If you find this project helpful, consider donating PayPal.
Dependencies
~0.7–12MB
~156K SLoC