docs(providers): add doctests and examples

This commit is contained in:
Georgios Konstantopoulos 2020-06-10 10:10:33 +03:00
parent 980e7fca8c
commit f93b8b6919
No known key found for this signature in database
GPG Key ID: FA607837CD26EDBC
3 changed files with 89 additions and 27 deletions

View File

@ -1,5 +1,29 @@
//! Minimal HTTP JSON-RPC 2.0 Client //! Minimal HTTP JSON-RPC 2.0 Client
//! The request/response code is taken from [here](https://github.com/althea-net/guac_rs/blob/master/web3/src/jsonrpc) //! The request/response code is taken from [here](https://github.com/althea-net/guac_rs/blob/master/web3/src/jsonrpc)
//!
//! If interacting with Ethereum, consider using the
//! [`Provider`](../struct.Provider.html) struct instead.
//!
//! # Example
//!
//! ```no_run
//! use ethers_providers::{JsonRpcClient, http::{Provider, ClientError}};
//! use ethers_core::types::U64;
//! use std::str::FromStr;
//!
//! async fn get_block(provider: &Provider) -> Result<U64, ClientError> {
//! let block_number: U64 = provider.request("eth_blockNumber", None::<()>).await?;
//! Ok(block_number)
//! }
//!
//! # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
//! let provider = Provider::from_str("http://localhost:8545")?;
//! let block = get_block(&provider).await?;
//! println!("{:?}", block);
//! # Ok(())
//! # }
//!
//! ```
use crate::{provider::ProviderError, JsonRpcClient}; use crate::{provider::ProviderError, JsonRpcClient};
use async_trait::async_trait; use async_trait::async_trait;
@ -8,12 +32,27 @@ use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use std::{ use std::{
fmt, fmt,
str::FromStr,
sync::atomic::{AtomicU64, Ordering}, sync::atomic::{AtomicU64, Ordering},
}; };
use thiserror::Error; use thiserror::Error;
use url::Url; use url::Url;
/// An HTTP Client /// A low-level JSON-RPC Client over HTTP.
///
/// # Example
///
/// ```no_run
/// use ethers_providers::{JsonRpcClient, http::Provider};
/// use ethers_core::types::U64;
/// use std::str::FromStr;
///
/// # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
/// let provider = Provider::from_str("http://localhost:8545")?;
/// let block_number: U64 = provider.request("eth_blockNumber", None::<()>).await?;
/// # Ok(())
/// # }
/// ```
#[derive(Debug)] #[derive(Debug)]
pub struct Provider { pub struct Provider {
id: AtomicU64, id: AtomicU64,
@ -29,7 +68,7 @@ pub enum ClientError {
ReqwestError(#[from] ReqwestError), ReqwestError(#[from] ReqwestError),
#[error(transparent)] #[error(transparent)]
/// Thrown if the response could not be parsed /// Thrown if the response could not be parsed
JsonRpcError(#[from] JsonRpcError), JsonRpcError(#[from] errors::JsonRpcError),
} }
impl From<ClientError> for ProviderError { impl From<ClientError> for ProviderError {
@ -68,6 +107,16 @@ impl JsonRpcClient for Provider {
impl Provider { impl Provider {
/// Initializes a new HTTP Client /// Initializes a new HTTP Client
///
/// # Example
///
/// ```
/// use ethers_providers::http::Provider;
/// use url::Url;
///
/// let url = Url::parse("http://localhost:8545").unwrap();
/// let provider = Provider::new(url);
/// ```
pub fn new(url: impl Into<Url>) -> Self { pub fn new(url: impl Into<Url>) -> Self {
Self { Self {
id: AtomicU64::new(0), id: AtomicU64::new(0),
@ -77,6 +126,15 @@ impl Provider {
} }
} }
impl FromStr for Provider {
type Err = url::ParseError;
fn from_str(src: &str) -> Result<Self, Self::Err> {
let url = Url::parse(src)?;
Ok(Provider::new(url))
}
}
impl Clone for Provider { impl Clone for Provider {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
@ -87,24 +145,29 @@ impl Clone for Provider {
} }
} }
#[derive(Serialize, Deserialize, Debug, Clone, Error)] // leak private type w/o exposing it
/// A JSON-RPC 2.0 error mod errors {
pub struct JsonRpcError { use super::*;
/// The error code
pub code: i64,
/// The error message
pub message: String,
/// Additional data
pub data: Option<Value>,
}
impl fmt::Display for JsonRpcError { #[derive(Serialize, Deserialize, Debug, Clone, Error)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// A JSON-RPC 2.0 error
write!( pub struct JsonRpcError {
f, /// The error code
"(code: {}, message: {}, data: {:?})", pub code: i64,
self.code, self.message, self.data /// The error message
) pub message: String,
/// Additional data
pub data: Option<Value>,
}
impl fmt::Display for JsonRpcError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"(code: {}, message: {}, data: {:?})",
self.code, self.message, self.data
)
}
} }
} }
@ -140,13 +203,13 @@ struct Response<T> {
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)] #[serde(untagged)]
enum ResponseData<R> { enum ResponseData<R> {
Error { error: JsonRpcError }, Error { error: errors::JsonRpcError },
Success { result: R }, Success { result: R },
} }
impl<R> ResponseData<R> { impl<R> ResponseData<R> {
/// Consume response and return value /// Consume response and return value
fn into_result(self) -> Result<R, JsonRpcError> { fn into_result(self) -> Result<R, errors::JsonRpcError> {
match self { match self {
ResponseData::Success { result } => Ok(result), ResponseData::Success { result } => Ok(result),
ResponseData::Error { error } => Err(error), ResponseData::Error { error } => Err(error),

View File

@ -19,9 +19,8 @@ pub trait JsonRpcClient: Debug + Clone {
type Error: Error + Into<ProviderError>; type Error: Error + Into<ProviderError>;
/// Sends a request with the provided JSON-RPC and parameters serialized as JSON /// Sends a request with the provided JSON-RPC and parameters serialized as JSON
async fn request<T: Serialize + Send + Sync, R: for<'a> Deserialize<'a>>( async fn request<T, R>(&self, method: &str, params: Option<T>) -> Result<R, Self::Error>
&self, where
method: &str, T: Serialize + Send + Sync,
params: Option<T>, R: for<'a> Deserialize<'a>;
) -> Result<R, Self::Error>;
} }

View File

@ -17,7 +17,7 @@ use std::{convert::TryFrom, fmt::Debug};
/// An abstract provider for interacting with the [Ethereum JSON RPC /// An abstract provider for interacting with the [Ethereum JSON RPC
/// API](https://github.com/ethereum/wiki/wiki/JSON-RPC). Must be instantiated /// API](https://github.com/ethereum/wiki/wiki/JSON-RPC). Must be instantiated
/// with a [`Network`](networks/trait.Network.html) and a data transport /// with a data transport
/// (e.g. HTTP, Websockets etc.) /// (e.g. HTTP, Websockets etc.)
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Provider<P>(P, Option<Address>); pub struct Provider<P>(P, Option<Address>);