diff --git a/src/intro.md b/src/intro.md index 59631cc..65f37fe 100644 --- a/src/intro.md +++ b/src/intro.md @@ -52,6 +52,8 @@ community. It needs and welcomes help. For details see | [Serialize a `Url`][ex-url-serialize] | [![url-badge]][url] [![serde-badge]][serde] | [![cat-net-badge]][cat-net] [![cat-encoding-badge]][cat-encoding]| | [Make a HTTP GET request after parsing a URL][ex-url-basic] | [![reqwest-badge]][reqwest] | [![cat-net-badge]][cat-net] | | [Download a file to a temporary directory][ex-url-download] | [![reqwest-badge]][reqwest] [![tempdir-badge]][tempdir] | [![cat-net-badge]][cat-net] [![cat-filesystem-badge]][cat-filesystem] | +| [Query the GitHub API][ex-rest-get] | [![reqwest-badge]][reqwest] [![serde-badge]][serde] | [![cat-net-badge]][cat-net] [![cat-encoding-badge]][cat-encoding] | +| [Create and delete Gist with GitHub API][ex-rest-post] | [![reqwest-badge]][reqwest] [![serde-badge]][serde] | [![cat-net-badge]][cat-net] [![cat-encoding-badge]][cat-encoding] | ## [Application development](app.html) @@ -141,6 +143,8 @@ Keep lines sorted. [ex-rand-range]: basics.html#ex-rand-range [ex-rand-dist]: basics.html#ex-rand-dist [ex-rayon-iter-mut]: concurrency.html#ex-rayon-iter-mut +[ex-rest-get]: net.html#ex-rest-get +[ex-rest-post]: net.html#ex-rest-post [ex-std-read-lines]: basics.html#ex-std-read-lines [ex-toml-config]: encoding.html#ex-toml-config [ex-url-parse]: net.html#ex-url-parse diff --git a/src/net.md b/src/net.md index 96d1016..d907140 100644 --- a/src/net.md +++ b/src/net.md @@ -10,6 +10,8 @@ | [Serialize a `Url`][ex-url-serialize] | [![url-badge]][url] [![serde-badge]][serde] | [![cat-net-badge]][cat-net] [![cat-encoding-badge]][cat-encoding]| | [Make a HTTP GET request][ex-url-basic] | [![reqwest-badge]][reqwest] | [![cat-net-badge]][cat-net] | | [Download a file to a temporary directory][ex-url-download] | [![reqwest-badge]][reqwest] [![tempdir-badge]][tempdir] | [![cat-net-badge]][cat-net] [![cat-filesystem-badge]][cat-filesystem] | +| [Query the GitHub API][ex-rest-get] | [![reqwest-badge]][reqwest] [![serde-badge]][serde] | [![cat-net-badge]][cat-net] [![cat-encoding-badge]][cat-encoding] | +| [Create and delete Gist with GitHub API][ex-rest-post] | [![reqwest-badge]][reqwest] [![serde-badge]][serde] | [![cat-net-badge]][cat-net] [![cat-encoding-badge]][cat-encoding] | [ex-url-parse]: #ex-url-parse @@ -330,6 +332,122 @@ fn run() -> Result<()> { quick_main!(run); ``` +[ex-rest-get]: #ex-rest-get + +## Query the GitHub API + +[![reqwest-badge]][reqwest] [![serde-badge]][serde] [![cat-net-badge]][cat-net] [![cat-encoding-badge]][cat-encoding] + +GitHub [stargazers API v3](https://developer.github.com/v3/activity/starring/#list-stargazers) is queried with [`reqwest::get`] to obtain list of all users who have marked a GitHub project with a star. [`reqwest::Response`] is deserialized with [`Response::json`] into `User` objects implementing [`serde::Deserialize`]. + +```rust,no_run +#[macro_use] +extern crate serde_derive; +extern crate reqwest; + +#[derive(Deserialize, Debug)] +struct User { + login: String, + id: u32, + // remaining fields not deserialized for brevity +} + +fn run() -> reqwest::Result<()> { + let request_url = format!("https://api.github.com/repos/{owner}/{repo}/stargazers", + owner = "brson", + repo = "rust-cookbook"); + println!("{}", request_url); + let mut response = reqwest::get(&request_url)?; + + let users: Vec = response.json()?; + println!("{:?}", users); + Ok(()) +} + +fn main() { + run().unwrap(); +} +``` + +[ex-rest-post]: #ex-rest-post + +## Create and delete Gist with GitHub API + +[![reqwest-badge]][reqwest] [![serde-badge]][serde] [![cat-net-badge]][cat-net] [![cat-encoding-badge]][cat-encoding] + +HTTP POST request to [gists API v3](https://developer.github.com/v3/gists/) is made with [`reqwest::Client`] in order to create a gist. +A request body is created with [`serde_json::json!`] macro and +set set with [`RequestBuilder::json`]. +Request is prepared with [`Client::post`], authenticated with [`RequestBuilder::basic_auth`] and synchronously executed with [`RequestBuilder::send`]. + +Gist is subsequently deleted with HTTP DELETE request prepared with [`Client::delete`] and executed as before. + +```rust,no_run +#[macro_use] +extern crate error_chain; +extern crate reqwest; +#[macro_use] +extern crate serde_derive; +#[macro_use] +extern crate serde_json; + +use std::env; + +error_chain! { + foreign_links { + EnvVar(env::VarError); + HttpReqest(reqwest::Error); + } +} + +#[derive(Deserialize, Debug)] +struct Gist { + id: String, + html_url: String, + // remaining fields not deserialized for brevity +} + +fn run() -> Result<()> { + let gh_user = env::var("GH_USER")?; + let gh_pass = env::var("GH_PASS")?; + + // The type `gist_body` is `serde_json::Value` + let gist_body = json!({ + "description": "the description for this gist", + "public": true, + "files": { + "main.rs": { + "content": r#"fn main() { println!("hello world!");}"# + } + }}); + + // create the gist + let request_url = "https://api.github.com/gists"; + let client = reqwest::Client::new()?; + let mut response = client + .post(request_url) + .basic_auth(gh_user.clone(), Some(gh_pass.clone())) + .json(&gist_body) + .send()?; + + let gist: Gist = response.json()?; + println!("Created {:?}", gist); + + // delete the gist + let request_url = format!("{}/{}",request_url, gist.id); + let client = reqwest::Client::new()?; + let response = client + .delete(&request_url) + .basic_auth(gh_user, Some(gh_pass)) + .send()?; + + println!("Gist {} deleted! Status code: {}",gist.id, response.status()); + Ok(()) +} + +quick_main!(run); +``` + [cat-encoding-badge]: https://img.shields.io/badge/-encoding-red.svg @@ -360,9 +478,18 @@ quick_main!(run); [`origin`]: https://docs.rs/url/1.*/url/struct.Url.html#method.origin [`join`]: https://docs.rs/url/1.*/url/struct.Url.html#method.join [`reqwest::get`]: https://docs.rs/reqwest/*/reqwest/fn.get.html +[`reqwest::Client`]: https://docs.rs/reqwest/*/reqwest/struct.Client.html [`reqwest::Response`]: https://docs.rs/reqwest/*/reqwest/struct.Response.html [`Response::url`]: https://docs.rs/reqwest/*/reqwest/struct.Response.html#method.url +[`Response::json`]: https://docs.rs/reqwest/*/reqwest/struct.Response.html#method.json +[`RequestBuilder::basic_auth`]: https://docs.rs/reqwest/*/reqwest/struct.RequestBuilder.html#method.basic_auth +[`Client::delete`]: https://docs.rs/reqwest/*/reqwest/struct.Client.html#method.delete +[`Client::post`]: https://docs.rs/reqwest/*/reqwest/struct.Client.html#method.post +[`RequestBuilder::json`]: https://docs.rs/reqwest/*/reqwest/struct.RequestBuilder.html#method.json +[`RequestBuilder::send`]: https://docs.rs/reqwest/*/reqwest/struct.RequestBuilder.html#method.send [`read_to_string`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_to_string [`String`]: https://doc.rust-lang.org/std/string/struct.String.html +[`serde::Deserialize`]: https://docs.rs/serde/*/serde/trait.Deserialize.html +[`serde_json::json!`]: https://docs.rs/serde_json/*/serde_json/macro.json.html [`TempDir::new`]: https://docs.rs/tempdir/*/tempdir/struct.TempDir.html#method.new [`TempDir::path`]: https://docs.rs/tempdir/*/tempdir/struct.TempDir.html#method.path