1 unstable release

Uses old Rust 2015

0.1.0 Oct 31, 2018

#54 in #json-api

MIT/Apache

18KB
255 lines

Breadboard 🍞🛹

Breadboard is a simple JSON API request router for hyper.

Perhaps it will become less simple later.

It is in early development but you might find it useful. Your feedback is welcomed.


lib.rs:

Breadboard is a simple JSON API request router for hyper.

Like electronics breadboards, Breadboard is well-suited to prototyping your API. Also like electronics breadboards, its functionality is limited and if you bend it too hard it will snap.

To create a hyper Service, create a Breadboard with Breadboard::new, use methods like Breadboard::get to add handlers, then use it in hyper::server::Builder::serve.

Quick start

extern crate breadboard;
extern crate hyper;

use breadboard::Breadboard;
use hyper::server::Server;
use hyper::{Request, Response};
use std::string::ParseError; // waiting for `!`

fn hello(_: Request<()>) -> Result<Response<&'static str>, ParseError> {
    Ok(Response::new("Hello, world!"))
}

let board = Breadboard::new().get("/", hello);
let server = Server::bind(&"127.0.0.1:3000".parse().unwrap())
    .serve(board);
// hyper::rt::run(server.map_err(|e| eprintln!("server error: {}", e)));

You can also use closures as handlers:

let board = Breadboard::new().get(
    "/",
    |_: Request<()>| -> Result<Response<&'static str>, ParseError> {
        Ok(Response::new("Hello, world!"))
    },
);
let server = Server::bind(&"127.0.0.1:3000".parse().unwrap())
    .serve(board);

Handlers that return Futures

Handlers return a type that implement IntoFuture. This includes Result, as well as all types that implement Future.

This example handler makes an HTTP request and responds with the response it receives. It returns a Future that resolves after the request completes.

extern crate breadboard;
extern crate hyper;

use breadboard::Breadboard;
use hyper::client::Client;
use hyper::rt::{Future, Stream};
use hyper::server::Server;
use hyper::{Body, Request, Response};

fn proxy(_: Request<()>) -> impl Future<Item = Response<Vec<u8>>, Error = hyper::Error> {
    let client: Client<_, Body> = Client::builder().build_http();
    client
        .get("http://icanhazip.com/".parse().unwrap())
        .and_then(|response| {
            let (parts, body) = response.into_parts();
            body.concat2()
                .map(|chunk| Response::from_parts(parts, chunk.into_bytes().to_vec()))
        })
}

let board = Breadboard::new().get("/", proxy);
let server = Server::bind(&"127.0.0.1:3000".parse().unwrap())
    .serve(board);

Deserialize and Serialize

The real power of Breadboard is that request and response bodies can be anything as long as they implement Deserialize and Serialize, respectively.

extern crate breadboard;
extern crate hyper;
extern crate serde;
#[macro_use]
extern crate serde_derive;

use breadboard::Breadboard;
use hyper::client::Client;
use hyper::rt::{Future, Stream};
use hyper::server::Server;
use hyper::{Body, Request, Response};
use std::string::ParseError; // waiting for `!`

#[derive(Debug, Deserialize)]
struct Message {
    message: String,
}

fn message(request: Request<Message>) -> Result<Response<String>, ParseError> {
    Ok(Response::new(request.into_body().message))
}

let board = Breadboard::new().post("/", message);
let server = Server::bind(&"127.0.0.1:3000".parse().unwrap())
    .serve(board);

Dependencies

~8.5MB
~153K SLoC