cyberarbitarge / binance.rs

binance rust connector
Apache License 2.0
0 stars 2 forks source link

Rest interface proc-macro to reduce the builder implementation redundancy #2

Open g302ge opened 2 years ago

g302ge commented 2 years ago

At a glance, the template code is below

#[derive(Debug, RestApi, Default)]
#[rest(uri="rest_api/path")
#[rest(method="GET")
#[rest(signature="USER_DATA")]
pub struct SomeRestApiName {
        // we belive that every field should implement the Default trait as default value 
        // else use Option as optional semantic
        field1: String,
        field2: Option<i32>,
        // other fields
}

Then we should get the api class with builder as below:

impl RestApi for SomeRestApiName {
         fn uri(&self) -> String { // return the uri in attribute }
         fn method(&self) -> reqwest::Method { // return the method in attribute }
         fn wait_to_sign(&self) -> Option<String> {
                    // hmacsha256 for USER_DATA in binance defined
         }
         fn query() -> Option<String>
         fn body() -> Option<String>

}

impl SomeRestApiName {
       pub fn new() -> Self; // Default ?
       pub fn field1(mut self, type) -> Self;
       pub fn field2(mut self, type) -> Self; 
}

So we could use this directly in Client look like this

async fn main() {
      async {
              let mut request = SomeRestApiName::new()
                                            .field1(xxxx)
                                            .field2(xxx);
             client.execute(&request).unwrap();
      }
}
g302ge commented 2 years ago

Impl note: in the plain Java implementation constructed by Binance official developer. There is a fact, that every Rest api will return a simple text response, maybe the json format but not consistency for all

g302ge commented 2 years ago

and the response struct is more like this

#[response]
pub enum Response {
        Error(BinanceError),
        Success{
           // other fields 
        }
}
g302ge commented 2 years ago

Hold on, firstly we have to implement a new proc-macro library to generate the redundance code template for any exchange like rest interfaces

g302ge commented 2 years ago

recent desgin

#[derive(Debug, RestApi, Default)]
#[rest(uri="rest_api/path")
#[rest(method="GET")
#[rest(signature="USER_DATA")]
#[rest(respone="crate::spot::SomeRestApiNameResponse")]
pub struct SomeRestApiName {
        // we belive that every field should implement the Default trait as default value 
        // else use Option as optional semantic
        field1: String,
        field2: Option<i32>,
        // other fields
}

Derive into

#[derive(Debug, Default, serde::Serialize)
pub struct SomeRestApiName {
      // fields 
}

#[derive(Default)]
pub struct SomeRestApiNameBuilder {
       // fields in Rest 
}

impl SomeRestApiNameBuilder {
         // fields builders 
}

impl SomeRestApiName {
      pub fn builder() -> SomeRestApiNameBuilder
}

impl SomeRestApiName {
       pun fn execute<T: RestClient>(&self. client: &T) -> Result<SomeRestApiNameResponse> {
             // calculate the signature if not ignore and add header
             // do execute 
             // serde_json::from_str() -> to response 
      }
}