- Open the Cargo.toml file that has been generated for you
- Under [dependencies], if you didn't do so in the last recipe, add the following lines:
reqwest = "0.8.5"
serde = "1.0.30"
serde_derive = "1.0.30"
- If you want, you can go to request's (https://crates.io/crates/reqwest), serde's (https://crates.io/crates/serde), and serde_derive's (https://crates.io/crates/serde_derive) crates.io pages to check for the newest versions and use those ones instead
- In the folder src/bin, create a file called making_requests.rs
- Add the following code and run it with cargo run --bin making_requests:
1 extern crate reqwest; 2 #[macro_use] 3 extern crate serde_derive; 4 5 use std::fmt; 6 7 #[derive(Serialize, Deserialize, Debug)] 8 // The JSON returned by the web service that hands posts out 9 // it written in camelCase, so we need to tell serde about that 10 #[serde(rename_all = "camelCase")] 11 struct Post { 12 user_id: u32, 13 id: u32, 14 title: String, 15 body: String, 16 } 17 18 #[derive(Serialize, Deserialize, Debug)] 19 #[serde(rename_all = "camelCase")] 20 struct NewPost { 21 user_id: u32, 22 title: String, 23 body: String, 24 } 25 26 #[derive(Serialize, Deserialize, Debug)] 27 #[serde(rename_all = "camelCase")] 28 // The following struct could be rewritten with a builder 29 struct UpdatedPost { 30 #[serde(skip_serializing_if = "Option::is_none")] 31 user_id: Option, 32 #[serde(skip_serializing_if = "Option::is_none")] 33 title: Option, 34 #[serde(skip_serializing_if = "Option::is_none")] 35 body: Option, 36 } 37 38 struct PostCrud { 39 client: reqwest::Client, 40 endpoint: String, 41 } 42 43 impl fmt::Display for Post { 44 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 45 write!( 46 f, 47 "User ID: {} ID: {} Title: {} Body: {} ", 48 self.user_id, self.id, self.title, self.body 49 ) 50 } 51 }
The following code shows the requests being implemented:
53 impl PostCrud { 54 fn new() -> Self { 55 PostCrud { 56 // Build an HTTP client. It's reusable! 57 client: reqwest::Client::new(), 58 // This is a link to a fake REST API service 59 endpoint:
"https://jsonplaceholder.typicode.com/posts".to_string(), 60 } 61 } 62 63 fn create(&self, post: &NewPost) -> Result<Post,
reqwest::Error> { 64 let response =
self.client.post(&self.endpoint).json(post).send()?.json()?; 65 Ok(response) 66 } 67 68 fn read(&self, id: u32) -> Result<Post, reqwest::Error> { 69 let url = format!("{}/{}", self.endpoint, id); 70 let response = self.client.get(&url).send()?.json()?; 71 Ok(response) 72 } 73 74 fn update(&self, id: u32, post: &UpdatedPost) -> Result<Post,
reqwest::Error> { 75 let url = format!("{}/{}", self.endpoint, id); 76 let response =
self.client.patch(&url).json(post).send()?.json()?; 77 Ok(response) 78 } 79 80 fn delete(&self, id: u32) -> Result<(), reqwest::Error> { 81 let url = format!("{}/{}", self.endpoint, id); 82 self.client.delete(&url).send()?; 83 Ok(()) 84 } 85 }
The following code shows us using our CRUD client:
87 fn main() { 88 let post_crud = PostCrud::new(); 89 let post = post_crud.read(1).expect("Failed to read post"); 90 println!("Read a post: {}", post); 91 92 let new_post = NewPost { 93 user_id: 2, 94 title: "Hello World!".to_string(), 95 body: "This is a new post, sent to a fake JSON API
server. ".to_string(), 96 }; 97 let post = post_crud.create(&new_post).expect("Failed to
create post"); 98 println!("Created a post: {}", post); 99 100 let updated_post = UpdatedPost { 101 user_id: None, 102 title: Some("New title".to_string()), 103 body: None, 104 }; 105 let post = post_crud 106 .update(4, &updated_post) 107 .expect("Failed to update post"); 108 println!("Updated a post: {}", post); 109 110 post_crud.delete(51).expect("Failed to delete post"); 111 }