implement cat api
This commit is contained in:
parent
22b26f791a
commit
e545b130f9
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "wow-such-doge"
|
||||
name = "i-can-has-cat"
|
||||
version = "0.0.1"
|
||||
authors = ["A. Malacoda <adrian.malacoda@monarch-pass.net>"]
|
||||
|
||||
@ -7,5 +7,5 @@ authors = ["A. Malacoda <adrian.malacoda@monarch-pass.net>"]
|
||||
reqwest = "0.8.0"
|
||||
serde = "1.0.14"
|
||||
serde_derive = "1.0.14"
|
||||
serde_json = "1.0.3"
|
||||
serde-xml-rs = "0.2.1"
|
||||
derive-error = "0.0.4"
|
||||
|
21
README.md
21
README.md
@ -1,17 +1,16 @@
|
||||
# Wow Such Doge
|
||||
[Dog API](https://dog.ceo/dog-api/) client in Rust.
|
||||
# I Can Has Cat
|
||||
[The Cat API](http://thecatapi.com/) client in Rust.
|
||||
|
||||
## Usage
|
||||
### Command Line
|
||||
* `cargo run`: output list of breeds
|
||||
* `cargo run <breed>` output all dogs of breed
|
||||
* `cargo run random`: output random dog
|
||||
* `cargo run random <breed>` output random dog of breed
|
||||
* `cargo run`: output list of categories
|
||||
* `cargo run random`: output random cat
|
||||
* `cargo run random <category>` output random cat of category
|
||||
|
||||
### Library
|
||||
|
||||
use wow_such_doge::Dogs;
|
||||
let dogs = Dogs::new();
|
||||
let breeds = Dogs::breeds();
|
||||
let random_dog = Dogs::random_image();
|
||||
let random_dog_of_breed = Dogs::random_image_by_breed("<breed>");
|
||||
use i_can_has_cat::Cats;
|
||||
let cats = Cats::new();
|
||||
let categories = cats.categories();
|
||||
let random_cat = cats.random_image();
|
||||
let random_cat_of_breed = cats.random_image_of_category("<category>");
|
||||
|
125
src/lib.rs
125
src/lib.rs
@ -1,61 +1,47 @@
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
extern crate serde_xml_rs;
|
||||
#[macro_use] extern crate serde_derive;
|
||||
extern crate reqwest;
|
||||
#[macro_use] extern crate derive_error;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io::Read;
|
||||
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
pub struct Dogs {
|
||||
pub struct Cats {
|
||||
url: String
|
||||
}
|
||||
|
||||
impl Dogs {
|
||||
pub fn new() -> Dogs {
|
||||
Dogs::with_url("https://dog.ceo/api/")
|
||||
impl Cats {
|
||||
pub fn new() -> Cats {
|
||||
Cats::with_url("http://thecatapi.com/api/")
|
||||
}
|
||||
|
||||
pub fn with_url(url: &str) -> Dogs {
|
||||
pub fn with_url(url: &str) -> Cats {
|
||||
let mut api_url = url.to_owned();
|
||||
if api_url.ends_with("/") {
|
||||
api_url.remove(url.len() - 1);
|
||||
}
|
||||
|
||||
Dogs {
|
||||
Cats {
|
||||
url: api_url
|
||||
}
|
||||
}
|
||||
|
||||
pub fn random_image(&self) -> Result<Image, Error> {
|
||||
Ok(self.make_call("/breeds/image/random")?.message)
|
||||
let mut response : Response<ImagesData> = self.make_call("/images/get?format=xml")?;
|
||||
Ok(response.data.images.images.remove(0))
|
||||
}
|
||||
|
||||
pub fn breeds(&self) -> Result<Breeds, Error> {
|
||||
Ok(self.make_call("/breeds/list/all")?.message)
|
||||
pub fn categories(&self) -> Result<Categories, Error> {
|
||||
let response : Response<CategoriesData> = self.make_call("/categories/list?format=xml")?;
|
||||
Ok(response.data.categories)
|
||||
}
|
||||
|
||||
pub fn subbreeds(&self, breed: &str) -> Result<Subbreeds, Error> {
|
||||
Ok(self.make_call(&format!("/breed/{}/list", breed))?.message)
|
||||
}
|
||||
|
||||
pub fn images_by_breed(&self, breed: &str) -> Result<Images, Error> {
|
||||
Ok(self.make_call(&format!("/breed/{}/images", breed))?.message)
|
||||
}
|
||||
|
||||
pub fn random_image_by_breed(&self, breed: &str) -> Result<Image, Error> {
|
||||
Ok(self.make_call(&format!("/breed/{}/images/random", breed))?.message)
|
||||
}
|
||||
|
||||
pub fn images_by_subbreed(&self, breed: &str, subbreed: &str) -> Result<Images, Error> {
|
||||
Ok(self.make_call(&format!("/breed/{}/{}/images", breed, subbreed))?.message)
|
||||
}
|
||||
|
||||
pub fn random_image_by_subbreed(&self, breed: &str, subbreed: &str) -> Result<Image, Error> {
|
||||
Ok(self.make_call(&format!("/breed/{}/{}/images/random", breed, subbreed))?.message)
|
||||
pub fn random_image_of_category(&self, category: &str) -> Result<Image, Error> {
|
||||
let mut response : Response<ImagesData> = self.make_call(&format!("/images/get?format=xml&category={}", category))?;
|
||||
Ok(response.data.images.images.remove(0))
|
||||
}
|
||||
|
||||
fn make_call<T>(&self, endpoint: &str) -> Result<Response<T>, Error>
|
||||
@ -69,21 +55,11 @@ impl Dogs {
|
||||
let mut content = String::new();
|
||||
response.read_to_string(&mut content)?;
|
||||
|
||||
let parsed_response: Response<T> = serde_json::from_str(&content)?;
|
||||
if parsed_response.is_success() {
|
||||
Ok(parsed_response)
|
||||
} else {
|
||||
Err(Error::API(serde_json::from_str(&content)?))
|
||||
}
|
||||
let parsed_response: Response<T> = serde_xml_rs::deserialize(content.as_bytes())?;
|
||||
Ok(parsed_response)
|
||||
}
|
||||
}
|
||||
|
||||
pub type Breed = String;
|
||||
pub type Image = String;
|
||||
pub type Images = Vec<Image>;
|
||||
pub type Subbreeds = Vec<String>;
|
||||
pub type Breeds = HashMap<Breed, Subbreeds>;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
/// HTTP request failed
|
||||
@ -91,7 +67,7 @@ pub enum Error {
|
||||
/// IO error
|
||||
IO(std::io::Error),
|
||||
/// Failed to parse
|
||||
Parse(serde_json::Error),
|
||||
Parse(serde_xml_rs::Error),
|
||||
/// Error from API
|
||||
API(APIError)
|
||||
}
|
||||
@ -123,12 +99,67 @@ impl Display for APIError {
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct Response<T> {
|
||||
status: String,
|
||||
message: T
|
||||
data: T
|
||||
}
|
||||
|
||||
impl<T> Response<T> {
|
||||
pub fn is_success(&self) -> bool {
|
||||
self.status == "success"
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct ImagesData {
|
||||
images: Images
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Images {
|
||||
#[serde(rename="image")]
|
||||
images: Vec<Image>
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Image {
|
||||
id: String,
|
||||
url: String,
|
||||
source_url: String
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct CategoriesData {
|
||||
categories: Categories
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Categories {
|
||||
#[serde(rename="category")]
|
||||
categories: Vec<Category>
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Category {
|
||||
id: String,
|
||||
name: String
|
||||
}
|
||||
|
||||
mod test {
|
||||
use serde_xml_rs;
|
||||
use {Image, Images};
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_cat () {
|
||||
let xml = r#"<image>
|
||||
<url>http://25.media.tumblr.com/tumblr_m99be6qgNT1qejbiro1_500.jpg</url>
|
||||
<id>MjA0MjYyMA</id>
|
||||
<source_url>http://thecatapi.com/?id=MjA0MjYyMA</source_url>
|
||||
</image>"#;
|
||||
let cat: Image = serde_xml_rs::deserialize(xml.as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_cats () {
|
||||
let xml = r#"<images>
|
||||
<image>
|
||||
<url>http://25.media.tumblr.com/tumblr_m99be6qgNT1qejbiro1_500.jpg</url>
|
||||
<id>MjA0MjYyMA</id>
|
||||
<source_url>http://thecatapi.com/?id=MjA0MjYyMA</source_url>
|
||||
</image>
|
||||
</images>"#;
|
||||
let cats: Images = serde_xml_rs::deserialize(xml.as_bytes()).unwrap();
|
||||
}
|
||||
}
|
||||
|
24
src/main.rs
24
src/main.rs
@ -1,27 +1,17 @@
|
||||
extern crate wow_such_doge;
|
||||
use wow_such_doge::Dogs;
|
||||
extern crate i_can_has_cat;
|
||||
use i_can_has_cat::Cats;
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
let dogs = Dogs::new();
|
||||
let cats = Cats::new();
|
||||
match env::args().nth(1).as_ref().map(|arg| arg.as_str()) {
|
||||
Some("random") => {
|
||||
match env::args().nth(2).as_ref().map(|arg| arg.as_str()) {
|
||||
Some(breed) => {
|
||||
match env::args().nth(3).as_ref().map(|arg| arg.as_str()) {
|
||||
Some(subbreed) => println!("{}", dogs.random_image_by_subbreed(breed, subbreed).unwrap()),
|
||||
None => println!("{}", dogs.random_image_by_breed(breed).unwrap())
|
||||
}
|
||||
},
|
||||
None => println!("{}", dogs.random_image().unwrap())
|
||||
Some(category) => println!("{:?}", cats.random_image_of_category(category).unwrap()),
|
||||
None => println!("{:?}", cats.random_image().unwrap())
|
||||
}
|
||||
},
|
||||
Some(breed) => {
|
||||
match env::args().nth(2).as_ref().map(|arg| arg.as_str()) {
|
||||
Some(subbreed) => println!("{:?}", dogs.images_by_subbreed(breed, subbreed).unwrap()),
|
||||
None => println!("{:?}", dogs.images_by_breed(breed).unwrap())
|
||||
}
|
||||
},
|
||||
None => println!("{:?}", dogs.breeds())
|
||||
Some(_) => println!("{:?}", cats.categories()),
|
||||
None => println!("{:?}", cats.categories())
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user