We want to list all articles related to a keyword by making a call to a news API
- serialization / deserialization
- make HTTP request
We are going to use Hacker news API described here :
The results are in Json
An example with Curl :
curl -i https://hn.algolia.com/api/v1/search?query=rustHeaders :
HTTP/2 200
date: Wed, 05 Apr 2023 12:31:00 GMT
content-type: application/json; charset=utf-8We can check that content-type is Json.
Look at the HTTP body content :
{
hits:
[
{
title: "Y Combinator",
url: "http://ycombinator.com",
author: "pg",
points: 57,
story_text: null,
comment_text: null,
_tags:
[
"story"
],
num_comments: 2,
objectID: "1",
_highlightResult:
{
title:
{
value: "Y Combinator",
matchLevel: "none",
matchedWords: [ ]
},
url:
{
value: "http://ycombinator.com",
matchLevel: "none",
matchedWords: [ ]
},
author:
{
value: "<em>pg</em>",
matchLevel: "full",
matchedWords:
[
"pg"
]
}
}
}, [...]
],
page: 0,
nbHits: 11,
nbPages: 1,
hitsPerPage: 20,
processingTimeMS: 1,
query: "pg",
params: "query=pg"
}We need to parse the body of the HTTP response provided as Json String into our data structure in Rust.
=> This a Deserialisation
Serde is a framework for serializing and deserializing Rust data structures efficiently and generically.
Serde provides a derive macro to generate implementations of the Serialize and Deserialize traits for data structures defined in your crate, allowing them to be represented conveniently in all of Serde's data formats.
Add Serde dependency with derive feature :
cargo add serde -F deriveOur data structure is composed of numbers of hits and a collection of articles
We need to define our data structure representing the Json Response :
#[derive(Debug, Deserialize)]
pub struct Article {
pub title: String,
}💡 we don't need to map every field. Others fields are ignored.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SearchResult {
pub nb_hits: u64,
pub hits: Vec<Article>,
}💡 We use a macro rename_all to rename deserialized string from a camelCase convention to a Rust snake_case convention
📚 Additional resources
- Serde documentation (ex: specify version, features,etc)
- curl documentation
The reqwest crate provides a convenient, higher-level HTTP Client.
We need to add our library to our project :
cargo add reqwest -F json blocking💡 Reqwest supports async and blocking requests. For now, we use a blocking client.
Example of GET HTTP request :
// format valid URL
let query = format!("https://hn.algolia.com/api/v1/search?query={}", keyword);
// execute HTTP call
let http_response: Result<Result, Error> = reqwest::blocking::get(query);
// Try to deserialize if response success
match http_response {
Ok(response) => response.json::<SearchResult>(),
Err(e) => Err(e),
}We have to deal with two types of Error :
- error when doing HTTP call
- error when deserializing
When first error occurs we don't want to try deserialization. It breaks the logic flow.
To avoid spaghetti code we can use question mark ? operator :
let query = format!("https://hn.algolia.com/api/v1/search?query={}", keyword);
let http_response = reqwest::blocking::get(query)?;
let search_results: SearchResult = http_response.json::<SearchResult>()?;📚 Additional resources
We expect to make a search with a keyword :
cargo run -- search --keyword <whatever>💡 Tips :
- update command to add
search - implement the
search_newsfunction in a newsearchmodule - manage errors messages
- create a function to display results as list
Use Cli Table to display results as table
cargo run -- search --keyword rust
+----------------------------------------------------------------------------+
| Title |
+----------------------------------------------------------------------------+
| Why Discord is switching from Go to Rust |
+----------------------------------------------------------------------------+
| A half-hour to learn Rust |
+----------------------------------------------------------------------------+
you can connect your app to any API now !
Check a solution with unit tests here
What you learned
- serialization and deserialization with serde
- make http call with reqwest
- use question mark to manage Errors