Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

README.md

Make Api call

We want to list all articles related to a keyword by making a call to a news API

🎯 Objectives

  • serialization / deserialization
  • make HTTP request

Our API

We are going to use Hacker news API described here :

https://hn.algolia.com/api

The results are in Json

An example with Curl :

curl -i https://hn.algolia.com/api/v1/search?query=rust

Headers :

HTTP/2 200
date: Wed, 05 Apr 2023 12:31:00 GMT
content-type: application/json; charset=utf-8

We 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

Serialisation / deserialization

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 derive

Our 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

Make an HTTP request

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

📝 Exercice : Update application to add a search command

We expect to make a search with a keyword :

cargo run -- search --keyword <whatever>

💡 Tips :

  • update command to add search
  • implement the search_news function in a new search module
  • manage errors messages
  • create a function to display results as list

📝 Exercice : display search results as table

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                                                  |
+----------------------------------------------------------------------------+

👏 Congrats

you can connect your app to any API now !

Check a solution with unit tests here

📝 Summary

What you learned

  • serialization and deserialization with serde
  • make http call with reqwest
  • use question mark to manage Errors