Skip to content
This repository has been archived by the owner on Nov 18, 2019. It is now read-only.
/ courier Public archive

Automatically derive `FromData` and `Responder` for custom types.

Notifications You must be signed in to change notification settings

randomPoison/courier

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rocket Derive

courier is a utility crate for the Rocket framework which allows you derive FromData and Responder for your custom types. Here's an example using courier to handle sending and recieving custom data to/from the client:

#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;
#[macro_use]
extern crate courier;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

#[derive(Deserialize, FromData)]
pub struct CustomRequest {
    pub foo: String,
    pub bar: usize,
}

#[derive(Serialize, Responder)]
pub struct CustomResponse {
    pub baz: usize,
}

#[post("/endpoint", data = "<request>")]
pub fn handle_request(request: CustomRequest) -> CustomResponse {
    if request.foo == "foo" {
        CustomResponse { baz: 0 }
    } else {
        CustomResponse { baz: request.bar }
    }
}

In this example, the response will be encoded the same way that the request was, e.g. if the client sent the request body as JSON, then the response will be sent as JSON.

Usage

Add courier, as well as the relevant Serde crates to your Cargo.toml:

[dependencies]
courier = "0.3.1"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"

Import the crates into your project:

#[macro_use]
extern crate courier;

extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

Note that you must have the #[macro_use] attribute on the extern crate statement in order to use this crate's features.

You can now use #[derive(FromData)] and #[derive(Responder)] for your custom types.

Supported Formats

courier supports receiving request bodies and sending response bodies in multiple formats. For each one you'd like to enable, you'll have to enable a feature in your Cargo.toml and add the relevant Serde crate(s) to your project. The following table shows which formats are currently supported, the feature name for that format, and what Serde crate(s) you'll need to include.

Format Feature Name Serde Crate(s)
JSON json serde_json
MessagePack msgpack rmp-serde

By default, only JSON support is enabled. So, for example, if you'd like to add MessagePack support, you'd edit your Cargo.toml to enable the msgpack feature and add rmp-serde as a dependency:

[dependencies]
rmp-serde = "0.13.6"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"

[dependencies.courier]
version = "0.3.1"
features = ["msgpack"]

And then add rmp-serde to your project root:

#[macro_use]
extern crate courier;

extern crate rmp_serde;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

Note that, to also support JSON, you still need to include serde_json as a dependency. If you do not wish to support JSON, you can specify default-features = false in your Cargo.toml:

[dependencies.courier]
version = "0.3.1"
default-features = false
features = ["msgpack"]

Using Multiple Formats

When multiple formats are enabled at once, the Content-Type header in the request is used to determine which format the request data is in, and the Accept header is used to determine which format to use for the response.

While this mostly removes the need for rocket_contrib::Json (and similar types), it is still possible to use it to override the behavior defined with courier. For example, say you specify a format for your Rocket route:

#[post("/endpoint", format = "application/json", data = "<request>")]
pub fn handle_request(request: CustomRequest) -> CustomResponse {
    if request.foo == "foo" {
        CustomResponse { baz: 0 }
    } else {
        CustomResponse { baz: request.bar }
    }
}

In that case, Rocket will check the content type before routing the request to handle_request, then the FromData impl for CustomRequest will check it again. If this isn't desirable, you can use rocket_contrib::Json to skip the second check:

use rocket_contrib::Json;

#[post("/endpoint", format = "application/json", data = "<request>")]
pub fn handle_request(request: Json<CustomRequest>) -> Json<CustomResponse> {
    if request.foo == "foo" {
        Json(CustomResponse { baz: 0 })
    } else {
        Json(CustomResponse { baz: request.bar })
    }
}

Note, though, that recommended to not explicitly specify the format parameter for your route if you're using courier. The code generated by courier allows you to write content type-agnostic route handlers, so manually specifying an expected format is unnecessary.

About

Automatically derive `FromData` and `Responder` for custom types.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages