Skip to content

Instantly share code, notes, and snippets.

@indiranell
Last active March 21, 2024 08:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save indiranell/de278fccde27f095ee7563afbf24690e to your computer and use it in GitHub Desktop.
Save indiranell/de278fccde27f095ee7563afbf24690e to your computer and use it in GitHub Desktop.
Rust code for Reqwest crate
//Rust script using reqwests to make Get and Post call to cars api to get and add cars
use std::fs;
use serde_derive::{Deserialize, Serialize};
use std::time::Duration;
use serde_json::Value as JsonValue;
#[derive(Debug, Deserialize)]
struct ApiConfig {
username: String,
password: String,
}
#[derive(Debug, Deserialize)]
struct Config {
api: ApiConfig,
}
#[derive(Debug, Deserialize, Serialize)]
struct Car {
brand: String,
car_type: String,
name: String,
price_range: String,
}
#[derive(Debug, Deserialize, Serialize)]
struct CarsResponse {
cars_list: Vec<Car>,
successful: bool,
}
#[tokio::main]
async fn main() {
let config_str = fs::read_to_string("config.toml").expect("Failed to read config file");
// convert string into a Config struct
let config: Config = toml::from_str(&config_str).expect("Failed to parse config");
// Read the username and password
let username = &config.api.username;
let password = &config.api.password;
match get_cars(username, password).await {
Ok(json_response) => {
if validate_get_response(&json_response) {
println!("Cars response is valid.");
println!("Cars: {:#?}", json_response);
} else {
println!("Invalid cars response structure.");
}
}
Err(err) => println!("Error: {}", err),
}
let json_data = r#"
{
"name": "Figo",
"brand": "Ford",
"price_range": "5-6lacs",
"car_type": "hatchback"
}
"#;
match add_cars(username, password, json_data).await {
Ok(response) => {
if validate_add_response(&response) {
println!("Car addition successful.");
println!("Response: {:#?}", response);
} else {
println!("Invalid car addition response structure.");
}
}
Err(err) => println!("Error: {}", err),
}
}
fn validate_get_response(cars_response: &JsonValue) -> bool {
// Validate that the JSON response has the expected structure
if let Ok(parsed_response) = serde_json::from_value::<CarsResponse>(cars_response.clone()) {
// Check if each Car object in cars_list has all required fields
for car in &parsed_response.cars_list {
if car.brand.is_empty() || car.car_type.is_empty() || car.name.is_empty() || car.price_range.is_empty() {
return false;
}
}
true
} else {
false
}
}
fn validate_add_response(response: &serde_json::Value) -> bool {
// Check if the response contains the successful response
if let Some(successful) = response.get("successful") {
if let Some(successful_bool) = successful.as_bool() {
return successful_bool;
}
}
false // If the expected field or type is missing, consider the response as invalid
}
async fn get_cars(username: &str, password: &str) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
// Read the content of the "config.toml" file into a string
let client = reqwest::Client::new();
let response = match client.get("http://localhost:5000/cars")
.basic_auth(username, Some(password))
.timeout(Duration::from_secs(10))
.send()
.await {
Ok(res) => {
// Check for specific status codes
if res.status().is_client_error() {
Err(format!("Server returned a client error: {}", res.status()).into())
} else if res.status().is_server_error() {
return Err(format!("Server returned a error, check your request data: {}", res.status()).into());
}
else {
Ok(res)
}
}
Err(err) => {
// Handle specific error types
if err.is_connect() {
return Err("Failed to connect to the server. Please make sure the server is running.".into());
}
else if err.is_timeout() {
return Err(format!("Request timed out: {}", err).into());
} else {
return Err(Box::new(err));
}
}
};
// Handle the response and extract JSON
let result_json: serde_json::Value = match response {
Ok(res) => match res.json().await {
Ok(json) => json,
Err(err) => return Err(Box::new(err)),
},
Err(err) => return Err(err),
};
Ok(result_json)
}
async fn add_cars(username: &str, password: &str, json_data: &str) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
let client = reqwest::Client::new();
let response = match client.post("http://localhost:5000/cars/add")
.basic_auth(username, Some(password))
.timeout(Duration::from_secs(10))
.header(reqwest::header::CONTENT_TYPE, "application/json")
.body(json_data.to_string())
.send()
.await {
Ok(res) => {
// Check for specific status codes
if res.status().is_client_error() {
return Err(format!("Server returned a client error: {}", res.status()).into());
}
else if res.status().is_server_error() {
return Err(format!("Server returned a error, check your request data: {}", res.status()).into());
} else {
Ok(res)
}
}
Err(err) => {
// Handle specific error types
if err.is_connect() {
return Err("Failed to connect to the server. Please make sure the server is running.".into());
} else if err.is_timeout() {
return Err(format!("Request timed out: {}", err).into());
}
else {
return Err(Box::new(err));
}
}
};
// Handle the response and extract JSON
let result_json: serde_json::Value = match response {
Ok(res) => match res.json().await {
Ok(json) => json,
Err(err) => return Err(Box::new(err)),
},
Err(err) => return Err(err),
};
Ok(result_json)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment