Return a hyper::Body of serde:Value - rust

In my situation, my function can only have signature:
pub async fn do_something(mut req: Request<Body>) -> Result<Response<Body>, CustomError> {
.....
}
I know how to return a body of string in my function as follow:
Ok(Response::new(Body::from("some string".to_string())))
However, something like this does not work with serde::Value; it only worked with strings.
What is the proper way to return a serde::Value while maintaining the same method signature?

You can serialize into BytesMut from the bytes crate, then convert into into Body:
use bytes::{BufMut, BytesMut};
let mut buf = BytesMut::new().writer();
serde_json::to_writer(&mut buf, &value)
.expect("serialization of `serde_json::Value` into `BytesMut` cannot fail");
Ok(Response::new(Body::from(buf.into_inner().freeze())))
If you can afford something less performant, you can serialize into Vec:
Ok(Response::new(Body::from(
serde_json::to_vec(&value).expect("serialization of `serde_json::Value` into `Vec` cannot fail"),
)))

Related

How to do proper error handling inside a map function? [duplicate]

This question already has answers here:
How does the Iterator::collect function work?
(2 answers)
Closed 1 year ago.
i want to read a textfile and convert all lines into int values.
I use this code.
But what i really miss here is a "good" way of error handling.
use std::{
fs::File,
io::{prelude::*, BufReader},
path::Path
};
fn lines_from_file(filename: impl AsRef<Path>) -> Vec<i32> {
let file = File::open(filename).expect("no such file");
let buf = BufReader::new(file);
buf.lines()
.map(|l| l.expect("Could not parse line"))
.map(|l:String| l.parse::<i32>().expect("could not parse int"))
.collect()
}
Question: How to do proper error handling ?
Is this above example "good rust code" ?
or should i use something like this :
fn lines_from_file(filename: impl AsRef<Path>) -> Vec<i32> {
let file = File::open(filename).expect("no such file");
let buf = BufReader::new(file);
buf.lines()
.map(|l| l.expect("Could not parse line"))
.map(|l:String| match l.parse::<i32>() {
Ok(num) => num,
Err(e) => -1 //Do something here
}).collect()
}
You can actually collect into a Result<T, E>.
See docs
So you could collect into a Result<Vec<i32>, MyCustomErrorType>.
This works when you transform your iterator in an iterator which returns a Result<i32, MyCustomErrorType>. The iteration stops at the first Err you map.
Here's your working code example.
I used the thiserror crate for error handling
use std::{
fs::File,
io::{prelude::*, BufReader},
num::ParseIntError,
path::Path,
};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum LineParseError {
#[error("Failed to read line")]
IoError(#[from] std::io::Error),
#[error("Failed to parse int")]
FailedToParseInt(#[from] ParseIntError),
}
fn lines_from_file(filename: impl AsRef<Path>) -> Result<Vec<i32>, LineParseError> {
let file = File::open(filename).expect("no such file");
let buf = BufReader::new(file);
buf.lines().map(|l| Ok(l?.parse()?)).collect()
}
Some small explanation of how the code works by breaking down this line of code:
buf.lines().map(|l| Ok(l?.parse()?)).collect()
Rust infers that we need to collect to a Result<Vec<i32>, LineParseError> because the return type of the function is Result<Vec<i32>, LineParseError>
In the mapping method we write l? this makes the map method return an Err if the l result contains an Err, the #[from] attribute on LineParseError::IoError takes care of the conversion
The .parse()? works the same way: #[from] on LineParseError::FailedToParseInt takes care of the conversion
Last but not least our method must return Ok(...) when the mapping does succeed, this makes the collect into a Result<Vec<i32>, LineParseError> possible.

How to return a Result containing a serde_json::Value?

This is what I have, but I want to avoid using unwrap on my reqwest values:
extern crate base64;
extern crate reqwest;
use serde_json;
use serde_json::json;
pub fn perform_get(id: String) -> serde_json::value::Value {
let client = reqwest::Client::builder().build().unwrap();
let url = String::from("SomeURL");
let res = client.get(&url).send().unwrap().text();
let mut v = json!(null);
match res {
Ok(n) => {
v = serde_json::from_str(&n).unwrap();
}
Err(r) => {
println!("Something wrong happened {:?}", r);
}
}
v
}
fn main() {
println!("Hi there! i want the function above to return a result instead of a Serde value so I can handle the error in main!");
}
Here is a link to a rust playground example
The official Rust book, The Rust Programming Language, is freely available online. It has an entire chapter on using Result, explaining introductory topics such as the Result enum and how to use it.
How to return a Result containing a serde_json::Value?
The same way you return a Result of any type; there's nothing special about Value:
use serde_json::json; // 1.0.38
pub fn ok_example() -> Result<serde_json::value::Value, i32> {
Ok(json! { "success" })
}
pub fn err_example() -> Result<serde_json::value::Value, i32> {
Err(42)
}
If you have a function that returns a Result, you can use the question mark operator (?) to exit early from a function on error, returning the error. This is a concise way to avoid unwrap or expect:
fn use_them() -> Result<(), i32> {
let ok = ok_example()?;
println!("{:?}", ok);
let err = err_example()?;
println!("{:?}", err); // Never executed, we always exit due to the `?`
Ok(()) // Never executed
}
This is just a basic example.
Applied to your MCVE, it would look something like:
use reqwest; // 0.9.10
use serde_json::Value; // 1.0.38
type Error = Box<dyn std::error::Error>;
pub fn perform_get(_id: String) -> Result<Value, Error> {
let client = reqwest::Client::builder().build()?;
let url = String::from("SomeURL");
let res = client.get(&url).send()?.text()?;
let v = serde_json::from_str(&res)?;
Ok(v)
}
Here, I'm using the trait object Box<dyn std::error::Error> to handle any kind of error (great for quick programs and examples). I then sprinkle ? on every method that could fail (i.e. returns a Result) and end the function with an explicit Ok for the final value.
Note that the panic and the never-used null value can be removed with this style.
See also:
What is this question mark operator about?
Rust proper error handling (auto convert from one error type to another with question mark)
Rust return result error from fn
Return value from match to Err(e)
What is the idiomatic way to handle/unwrap nested Result types?
better practice to return a Result
See also:
Should I avoid unwrap in production application?
If you are in the user side I would suggest to use Box<dyn std::error::Error>, this allow to return every type that implement Error, ? will convert the concrete error type to the dynamic boxed trait, this add a little overhead when there is an error but when error are not expected or really rare this is not a big deal.
use reqwest;
use serde_json::value::Value;
use std::error::Error;
fn perform_get(_id: String) -> Result<Value, Box<dyn Error>> {
let client = reqwest::Client::builder().build()?;
let url = String::from("SomeURL");
let res = client.get(&url).send()?.text()?;
let v = serde_json::from_str(&res)?;
Ok(v)
// last two line could be serde_json::from_str(&res).map_err(std::convert::Into::into)
}
fn main() {
println!("{:?}", perform_get("hello".to_string()));
}
This produce the following error:
Err(Error { kind: Url(RelativeUrlWithoutBase), url: None })
The kind smart folks over at Rust Discord helped me solve this one. (user noc)
extern crate base64;
extern crate reqwest;
pub fn get_jira_ticket() -> Result<serde_json::value::Value, reqwest::Error> {
let client = reqwest::Client::builder().build().unwrap();
let url = String::from("SomeURL");
let res = client.get(&url).send().and_then(|mut r| r.json());
res
}
fn main() {
println!("This works");
}
The key part was this in the header for the return
-> Result<serde_json::value::Value, reqwest::Error>
And this here to actually return the data.
client.get(&url).send().and_then(|mut r| r.json());

How can I return something meaningful from a generic function if there is nothing to return?

I'm building a library in Rust that has a send method that performs HTTP requests against a local RPC server using reqwest.
This method returns a generic type R in a Result where R: DeserializeOwned. After making the correct types for every response, serde_json::from_str() can get me the type.
If there is no response upon a request, how can I make send still return something meaningful?
This is the code I have now:
fn send<R, T>(
&self,
request: &RpcRequest<T>,
) -> Result<R, ApiError>
where
T: Serialize + Debug,
R: DeserializeOwned + Debug,
let res = serde_json::from_str(&buf).map_err(|err| ClientError::Json(err))
I am now forced to create and return an Err, but technically, the request returning no response is expected behavior, so I want to return something other than an Err.
I tried to work around this by wrapping R with Option, but that means I have to double unwrap every response, and 98% of the responses from reqwest do have data in their response, so it feels a bit like overkill.
I also tried to return a self-made EmptyResponse type, but the compiler complains: expected type R, found type EmptyResponse. I think returning a type EmptyResponse would be what I want, but maybe someone can shed some tips on how to maybe do this even better.
You can return an Result<Option<R>, ApiError> as shown in the documentation, then match it like this:
match sender.send(request) {
Ok(Some(r)) => {
// process response
}
Ok(None) => {
// process empty response
}
Err(e) => {
// process error
}
}
// or
if let Ok(Some(r)) = sender.send(request) {
// process response
}
I tried to work around this by wrapping R with Option, but that means I have to double unwrap every response, and 98% of the responses from reqwest do have data in their response, so it feels a bit like overkill.
Unwrapping the Option is a very cheap operation, there's nothing to be worried about.
The pragmatic answer is to have two functions:
fn send<R, T>(&self, request: &RpcRequest<T>) -> Result<R, ApiError>
where
T: Serialize + Debug,
R: DeserializeOwned + Debug,
fn send_no_response<T>(&self, request: &RpcRequest<T>) -> Result<(), ApiError>
where
T: Serialize + Debug,
If your server happens to return a value that can be deserialized into the type (), then you can avoid the overhead of two functions. However, this is not the case for JSON, one of the most common formats:
use serde::de::DeserializeOwned; // 1.0.85
use serde_json; // 1.0.37
type Error = Box<std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;
fn send<R>() -> Result<R, Error>
where
R: DeserializeOwned,
{
serde_json::from_str("").map_err(Into::into)
}
fn main() {
let _r: () = send().expect("Unable to deserialize");
}
This panics:
Unable to deserialize: Error("EOF while parsing a value", line: 1, column: 0)
In a world with specialization, you can use it and a helper trait to reduce back to one function:
#![feature(specialization)]
use serde::de::DeserializeOwned; // 1.0.85
use serde_json; // 1.0.37
type Error = Box<std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;
type ApiResponse = &'static str;
trait FromApi: Sized {
fn convert(response: ApiResponse) -> Result<Self, Error>;
}
impl<R> FromApi for R
where
R: DeserializeOwned,
{
default fn convert(response: ApiResponse) -> Result<R, Error> {
eprintln!("deserializing the response");
serde_json::from_str(response).map_err(Into::into)
}
}
impl FromApi for () {
fn convert(_response: ApiResponse) -> Result<Self, Error> {
eprintln!("Ignoring the response");
Ok(())
}
}
fn send<R: FromApi>() -> Result<R> {
eprintln!(r#""sending" the request"#);
let api_response = "";
R::convert(api_response)
}
fn main() {
let _r: () = send().expect("Unable to deserialize");
}

Idiomatic Rust method for handling references to a buffer

I would like to be able to construct objects that contain immutable references to a mutable buffer object. The following code does not work but illustrates my use case, is there an idiomatic Rust method for handling this?
#[derive(Debug)]
struct Parser<'a> {
buffer: &'a String
}
fn main() {
let mut source = String::from("Peter");
let buffer = &source;
let parser = Parser { buffer };
// How can I legally change source?
source.push_str(" Pan");
println!("{:?}", parser);
}
The golden rule of the rust borrow checker is: Only one writer OR multiple readers can access a resource at a time. This ensures that algorithms are safe to run in multiple threads.
You breach this rule here:
#[derive(Debug)]
struct Parser<'a> {
buffer: &'a String
}
fn main() {
// mutable access begins here
let mut source = String::from("Peter");
// immutable access begins here
let buffer = &source;
let parser = Parser { buffer };
source.push_str(" Pan");
println!("{:?}", parser);
// Both immutable and mutable access end here
}
If you are sure that your program doesn't actively access resources at the same time mutably and immutably, you can move the check from compile time to run time by wrapping your resource in a RefCell:
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
struct Parser {
buffer: Rc<RefCell<String>>
}
fn main() {
let source = Rc::new(RefCell::new(String::from("Peter")));
let parser = Parser { buffer: source.clone() };
source.borrow_mut().push_str(" Pan");
println!("{:?}", parser);
}
If you plan on passing your resource around threads, you can use an RwLock to block the thread until the resource is available:
use std::sync::{RwLock, Arc};
#[derive(Debug)]
struct Parser {
buffer: Arc<RwLock<String>>
}
fn main() {
let source = Arc::new(RwLock::new(String::from("Peter")));
let parser = Parser { buffer: source.clone() };
source.write().unwrap().push_str(" Pan");
println!("{:?}", parser);
}
On another note, you should prefer &str over &String
It's hard to tell what exactly you want to achieve by mutating the source; I would assume you don't want it to happen while the parser is doing its work? You can always try (depending on your specific use case) to separate the immutable from the mutable with an extra scope:
fn main() {
let mut source = String::from("Peter");
{
let buffer = &source;
let parser = Parser { buffer };
println!("{:?}", parser);
}
source.push_str(" Pan");
}
If you don't want to use RefCell, unsafe (or to simply keep a mutable reference to source in Parser and use that), I'm afraid it doesn't get better than plain refactoring.
To elaborate on how this can be done unsafely, what you've described can be achieved by using a raw const pointer to avoid the borrowing rules, which of course is inherently unsafe, as the very concept of what you've described is pretty unsafe. There are ways to make it safer though, should you choose this path. But I would probably default to using an Arc<RwLock> or Arc<Mutex> should safety be important.
use std::fmt::{self, Display};
#[derive(Debug)]
struct Parser {
buffer: *const String
}
impl Display for Parser {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let buffer = unsafe { &*self.buffer };
write!(f, "{}", buffer)
}
}
fn main() {
let mut source = String::from("Peter");
let buffer = &source as *const String;
let parser = Parser { buffer };
source.push_str(" Pan");
println!("{}", parser);
}

Trouble with buffer types in mio

I'd like to write an asynchronous server in Rust using mio and I have trouble with the buffer types. I've tried different buffer types and can't get it to work. My current code is:
extern crate mio;
extern crate bytes;
use std::io;
use std::io::{Error, ErrorKind};
use std::net::SocketAddr;
use std::str::FromStr;
use std::io::Cursor;
use self::mio::PollOpt;
use self::mio::EventLoop;
use self::mio::EventSet;
use self::mio::Token;
use self::mio::Handler;
use self::mio::io::TryRead;
use self::mio::io::TryWrite;
//use self::mio::buf::ByteBuf;
//use self::mio::buf::Buf;
use self::mio::tcp::*;
use self::bytes::buf::Buf;
use self::bytes::buf::byte::ByteBuf;
struct EventHandler;
impl Handler for EventHandler {
type Timeout = ();
type Message = ();
fn ready(&mut self, event_loop: &mut EventLoop<EventHandler>, token: Token, events: EventSet) {
}
}
pub struct Connection {
sock: TcpStream,
send_queue: Vec<ByteBuf>,
}
impl Connection {
pub fn writable(&mut self, event_loop: &mut EventLoop<EventHandler>) -> Result<(), String> {
while !self.send_queue.is_empty() {
if !self.send_queue.first().unwrap().has_remaining() {
self.send_queue.pop();
}
let buf = self.send_queue.first_mut().unwrap();
match self.sock.try_write_buf(&mut buf) {
Ok(None) => {
return Ok(());
}
Ok(Some(n)) => {
continue;
}
Err(e) => {
return Err(format!("{}", e));
}
}
}
Ok(())
}
}
fn main() {
println!("Hello, world!");
}
The Cargo.toml contains the following dependencies:
mio = "*"
bytes = "*"
which currently translates to bytes 0.2.11 and mio 0.4.3 in Cargo.lock.
The error I am getting is this:
main.rs:45:29: 45:52 error: the trait `bytes::buf::Buf` is not implemented
for the type `&mut bytes::buf::byte::ByteBuf` [E0277]
main.rs:45 match self.sock.try_write_buf(&mut buf) {
I'd want to be able to write a Vec<u8> into the socket and handle the case when the buffer is only partially written. How can I accomplish that?
I don't need explanation about the code that properly handles the return values, this question is about the buffer type. I have no idea which buffer type I have to use.
The problem is this:
let buf = self.send_queue.first_mut().unwrap();
match self.sock.try_write_buf(&mut buf) {
You pass in an &mut &mut ByteBuf to try_write_buf because buf is already an &mut ByteBuf. Just drop the extra &mut:
let buf = self.send_queue.first_mut().unwrap();
match self.sock.try_write_buf(buf) {

Resources