= Scryfall SDK for Rust :icons: font :toc: :sectanchors: :sectnums: :source-highlighter: highlight.js :highlightjs-theme: monokai-sublime image:https://img.shields.io/github/workflow/status/dgian/scryfall-sdk-rust/CI?label=CI&style=for-the-badge[Build Status (GitHub Actions),link=https://github.com/dgian/scryfall-sdk-rust/actions] image:https://img.shields.io/docsrs/scryfall_sdk_rust?label=docs.rs&style=for-the-badge[link="https://docs.rs/scryfall_sdk_rust"] image:https://img.shields.io/crates/v/scryfall_sdk_rust?style=for-the-badge[link="https://crates.io/crates/scryfall_sdk_rust"] This is a basic SDK written in https://www.rust-lang.org[Rust] for the amazing https://scryfall.com[Scryfall search-engine], a powerful search tool for Magic: The Gathering cards, sets etc. This SDK is implemented mainly for learning and practicing Rust skills. IMPORTANT: This is currently a WIP. == Requirements * *Minimum Rust version*: `1.61` == Usage First add the dependency to `Cargo.toml`: [source, toml] ---- [dependencies] scryfall_sdk_rust = "0.1" ---- The SDK exposes two HTTP clients using https://crates.io/crates/reqwest[reqwest crate]: [loweralpha] . async client (default) via `Scryfall` struct . blocking client via `ScryfallBlocking` struct NOTE: In order to use the blocking client you have to enable the `blocking` optional feature in Cargo.toml. [source, toml] ---- [dependencies] scryfall_sdk_rust = {version = "0.1", features = ["blocking"] } ---- === Examples In order to use the SDK, you have to take an instance of either client and make a request with it using one of the <<_resources, provided resources>>. For example: .Get a single card by Scryfall id (async) [source, rust] ---- use std::error::Error; use scryfall_sdk_rust::{CardResource, Scryfall}; #[tokio::main] // <1> async fn main() -> Result<(), Box> { let scryfall = Scryfall::default(); // <2> let card = scryfall.request( &CardResource::ById("f295b713-1d6a-43fd-910d-fb35414bf58a") ).await?; // <3> Ok(println!("{:?}", card)) } ---- <1> Using https://crates.io/crates/tokio[tokio runtime] for the examples, but you can use anyone you like <2> https://api.scryfall.com[Default scryfall api].You can also instantiate the client using `::from_url(&str)` to pass a custom url. <3> Make an async request to retrieve the card's data ==== Card search Scryfall provides a https://scryfall.com/docs/syntax[very powerful search syntax] which you can leverage in order to search for cards. *Note* currently the SDK provides only usage of row `q` string in the query parmaeter. Future versions will provide a Rust fluent api supporting the search keywords separately. .Find red creatures with 3 power (async) [source,rust] ---- use std::error::Error; use scryfall_sdk_rust::{CardPageResource, Scryfall}; use scryfall_sdk_rust::resources::cards::SearchQueryParams; #[tokio::main] async fn main() -> Result<(), Box> { let scryfall = Scryfall::default(); let search = CardPageResource::Search( SearchQueryParams::with_q("c%3Ared+pow%3D3") // <1> ); let cards = scryfall.request(&search).await?; Ok(println!("{:?}", cards)) } ---- <1> Construct the search query based on fulltext search syntax (c:red + pow=3) ==== Error response handling In the previous very basic examples, any kind of error, either an error response from the API, or a client error is propagated to the `Result` return of `main` function. This is done through the special `?` rust operator which propagates errors to the caller of a function. In reality, you will probably want to handle those errors at some point, at least the error responses (e.g. 404) from the API. The `request` function of both clients returns a `Result` which should contain either the Model for the expected object (e.g. Card) in case of success, or an `ErrorBody` in case of an error. For more info on the error response payloads (ErrorBody) see https://scryfall.com/docs/api/errors[Scryfall documentation]. An example of a possible error handling is the following [source,rust] ---- use std::error::Error; use scryfall_sdk_rust::{CardResource, Scryfall}; #[tokio::main] async fn main() -> Result<(), Box> { let scryfall = Scryfall::default(); let card = scryfall.request( &CardResource::ById("f295b713-1d6a-43fd-910d-fb35414bf58a") ).await; // <1> println!("{:?}", card .map_err(|e| format!("Error {}: {}", e.status, e.details) )); // <2> let error = scryfall.request( &CardResource::ById("invalid") ).await; // <3> Ok(println!("{:?}", error .map_err(|e| format!("Error {}: {}", e.status, e.details)) )) // <4> } ---- <1> Get the details for an existing card. Notice the absence of `?` after `await` as opposed to the previous example. <2> Printing here, will print the card details and not error as `map_err` does not affect the `Response::Ok` type of `Result` <3> Get the details of a non-existing card should return an error (404) <4> Printing here will print the details of the error response (status and detailed message) as the `Result` is now a `Response::Err` containing the respective `ErrorBody` For client errors, e.g. when the Scryfall API server cannot be resolved, or when the json response cannot be decoded for some reason, a special `ErrorBody` will be returned. This will have `code = CLIENT_ERR` and `status = 599` with `details` containing the original error cause. [#_resources] == List of implemented resources The following are currently implemented: - `CardResource` -> https://scryfall.com/docs/api/cards (single) - `CardPageResource` -> https://scryfall.com/docs/api/cards (page/search) - `CardCatalogResource` -> https://scryfall.com/docs/api/cards/autocomplete - `CardCollectionResource` -> https://scryfall.com/docs/api/cards/collection - `BulkDataListResource` -> https://scryfall.com/docs/api/bulk-data (list) - `BulkDataResource` -> https://scryfall.com/docs/api/bulk-data (single) - `CatalogResource` -> https://scryfall.com/docs/api/catalogs - `CardSymbolsResource` -> https://scryfall.com/docs/api/card-symbols/all - `ManaCostResource` -> https://scryfall.com/docs/api/card-symbols/parse-mana - `CardSetListResource` -> https://scryfall.com/docs/api/sets (list) - `CardSetResource` -> https://scryfall.com/docs/api/sets (single) - `RulingListResource` -> https://scryfall.com/docs/api/rulings