Merge pull request #80 from budziq/rest_github

Implemented two examples for "Query the GitHub API"
This commit is contained in:
David Tolnay 2017-05-16 08:32:54 -07:00 committed by GitHub
commit b56eb82073
2 changed files with 131 additions and 0 deletions

View file

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

View file

@ -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
<a name="ex-url-parse"/>
@ -330,6 +332,122 @@ fn run() -> Result<()> {
quick_main!(run);
```
[ex-rest-get]: #ex-rest-get
<a name="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<User> = response.json()?;
println!("{:?}", users);
Ok(())
}
fn main() {
run().unwrap();
}
```
[ex-rest-post]: #ex-rest-post
<a name="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);
```
<!-- Categories -->
[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