From b176d4df62390de2c51a139fdc4ae5727c20d08e Mon Sep 17 00:00:00 2001 From: Paul Oliver Date: Mon, 9 Aug 2021 11:39:42 +1200 Subject: [PATCH] WIP json using reqwest/serde --- native/Cargo.lock | 31 +++++++++++++++++++++++++++++++ native/Cargo.toml | 5 +++++ native/src/lib.rs | 11 ++++++++++- src/erqwest.erl | 2 ++ test/erqwest_SUITE.erl | 10 ++++++++++ 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/native/Cargo.lock b/native/Cargo.lock index 3a944b1..d4bdb8a 100644 --- a/native/Cargo.lock +++ b/native/Cargo.lock @@ -118,11 +118,16 @@ dependencies = [ name = "erqwest" version = "0.1.0" dependencies = [ + "bytes", "futures", "lazy_static", "reqwest", "rustler", "rustler_codegen", + "serde", + "serde-transcode", + "serde_json", + "serde_rustler", "tokio", ] @@ -616,6 +621,12 @@ dependencies = [ "url", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.9" @@ -824,6 +835,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-transcode" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "590c0e25c2a5bb6e85bf5c1bce768ceb86b316e7a01bdf07d2cb4ec2271990e2" +dependencies = [ + "serde", +] + [[package]] name = "serde_derive" version = "1.0.126" @@ -846,6 +866,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_rustler" +version = "0.1.0" +source = "git+https://github.com/satoren/serde_rustler?branch=rustler_0.22#0273c8aff4d9407f046dd9bf5d5f61d309d9a55f" +dependencies = [ + "lazy_static", + "quick-error", + "rustler", + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.0" diff --git a/native/Cargo.toml b/native/Cargo.toml index 7f3ff96..015b18d 100644 --- a/native/Cargo.toml +++ b/native/Cargo.toml @@ -11,6 +11,11 @@ crate-type = ["cdylib"] [dependencies] rustler = "0.22.0" rustler_codegen = "0.22.0" +bytes = "1.0.1" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +serde_rustler = { git = "https://github.com/satoren/serde_rustler", branch = "rustler_0.22" } +serde-transcode = "1.1" lazy_static = "1.0.0" reqwest = { version = "0.11", features = ["native-tls", "cookies"] } tokio = { version = "1", features = ["rt-multi-thread", "sync"] } diff --git a/native/src/lib.rs b/native/src/lib.rs index 428d6c2..c3df9c6 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -9,6 +9,7 @@ use std::sync::RwLock; use std::thread; use std::time::Duration; use tokio::runtime::{Handle, Runtime}; +use bytes::BufMut; mod atoms { rustler::atoms! { @@ -26,6 +27,7 @@ mod atoms { headers, https_only, identity, + json, method, ok, pool_idle_timeout, @@ -333,7 +335,14 @@ fn req_async_internal( }; if let Ok(term) = req.map_get(atoms::body().encode(env)) { req_builder = req_builder.body(term.decode::()?.as_slice().to_owned()); - }; + } else if let Ok(term) = req.map_get(atoms::json().encode(env)) { + let mut buf = vec![].writer(); + serde_transcode::transcode( + serde_rustler::Deserializer::from(term), + &mut serde_json::Serializer::new(&mut buf) + ).or(Err(rustler::Error::RaiseAtom("json_encode_error")))?; + req_builder = req_builder.body(buf.into_inner()); + } if let Ok(term) = req.map_get(atoms::timeout().encode(env)) { if let Some(timeout) = maybe_timeout(term.decode()?) { req_builder = req_builder.timeout(timeout); diff --git a/src/erqwest.erl b/src/erqwest.erl index 7c52823..aaf52a6 100644 --- a/src/erqwest.erl +++ b/src/erqwest.erl @@ -45,10 +45,12 @@ , method := method() , headers => [header()] , body => binary() + , json => term() , timeout => timeout_ms() }. -type req_opts() :: #{ headers => [header()] , body => binary() + , json => term() , timeout => timeout_ms() }. -type resp() :: #{ status := 100..599 diff --git a/test/erqwest_SUITE.erl b/test/erqwest_SUITE.erl index ae22a77..5714873 100644 --- a/test/erqwest_SUITE.erl +++ b/test/erqwest_SUITE.erl @@ -76,6 +76,7 @@ groups() -> , get_http , https_only , post + , json , timeout , timeout_default , timeout_infinity @@ -143,6 +144,15 @@ post(_Config) -> , body => <<"!@#$%^&*()">>}), #{<<"data">> := <<"!@#$%^&*()">>} = jsx:decode(Body). +json(_Config) -> + Json = #{<<"data">> => <<"!@#$%^&*()">>}, + {ok, #{status := 200, body := Body, headers := Headers}} = + erqwest:post(default, <<"https://httpbin.org/post">>, + #{json => Json}), + #{<<"data">> := JsonData} = jsx:decode(Body), + {<<"content-type">>, <<"application/json">>} = proplists:lookup(<<"content-type">>, Headers), + Json = jsx:decode(JsonData). + timeout(_Config) -> {error, #{code := timeout}} = erqwest:get(default, <<"https://httpbin.org/delay/1">>, #{timeout => 500}).