initial commit
This commit is contained in:
commit
14f905bc4a
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "wow-such-doge"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = ["A. Malacoda <adrian.malacoda@monarch-pass.net>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
reqwest = "0.8.0"
|
||||||
|
serde = "1.0.14"
|
||||||
|
serde_derive = "1.0.14"
|
||||||
|
serde_json = "1.0.3"
|
||||||
|
derive-error = "0.0.4"
|
17
README.md
Normal file
17
README.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Wow Such Doge
|
||||||
|
[Dog API](https://dog.ceo/dog-api/) 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
|
||||||
|
|
||||||
|
### 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>");
|
134
src/lib.rs
Normal file
134
src/lib.rs
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
extern crate serde;
|
||||||
|
extern crate serde_json;
|
||||||
|
#[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 {
|
||||||
|
url: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dogs {
|
||||||
|
pub fn new() -> Dogs {
|
||||||
|
Dogs::with_url("https://dog.ceo/api/")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_url(url: &str) -> Dogs {
|
||||||
|
let mut api_url = url.to_owned();
|
||||||
|
if api_url.ends_with("/") {
|
||||||
|
api_url.remove(url.len() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Dogs {
|
||||||
|
url: api_url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn random_image(&self) -> Result<Image, Error> {
|
||||||
|
Ok(self.make_call("/breeds/image/random")?.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn breeds(&self) -> Result<Breeds, Error> {
|
||||||
|
Ok(self.make_call("/breeds/list/all")?.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_call<T>(&self, endpoint: &str) -> Result<Response<T>, Error>
|
||||||
|
where for <'a> T: serde::Deserialize<'a> {
|
||||||
|
let mut response = reqwest::get(&format!(
|
||||||
|
"{}{}",
|
||||||
|
self.url,
|
||||||
|
endpoint
|
||||||
|
))?;
|
||||||
|
|
||||||
|
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)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Breed = String;
|
||||||
|
type Image = String;
|
||||||
|
type Images = Vec<Image>;
|
||||||
|
type Subbreeds = Vec<String>;
|
||||||
|
type Breeds = HashMap<Breed, Subbreeds>;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum Error {
|
||||||
|
/// HTTP request failed
|
||||||
|
HTTP(reqwest::Error),
|
||||||
|
/// IO error
|
||||||
|
IO(std::io::Error),
|
||||||
|
/// Failed to parse
|
||||||
|
Parse(serde_json::Error),
|
||||||
|
/// Error from API
|
||||||
|
API(APIError)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct APIError {
|
||||||
|
pub status: String,
|
||||||
|
pub code: String,
|
||||||
|
pub message: Option<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for APIError {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
self.message.as_ref().map(|message| message.as_str()).unwrap_or("")
|
||||||
|
}
|
||||||
|
fn cause(&self) -> Option<&std::error::Error> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for APIError {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
match self.message {
|
||||||
|
Some(ref message) => write!(f, "{}: {}", self.code, message),
|
||||||
|
None => write!(f, "{}", self.code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
struct Response<T> {
|
||||||
|
status: String,
|
||||||
|
message: T
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Response<T> {
|
||||||
|
pub fn is_success(&self) -> bool {
|
||||||
|
self.status == "success"
|
||||||
|
}
|
||||||
|
}
|
27
src/main.rs
Normal file
27
src/main.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
extern crate wow_such_doge;
|
||||||
|
use wow_such_doge::Dogs;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let dogs = Dogs::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(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())
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user