rocket-webapi

Making JSON webapi server with Rust and Rocket

Stars
11

Making a RESTful JSON API with Rust and Rocket

English

RocketWebWebAPI

Table of Contents

Setup

# rustup.
$ curl https://sh.rustup.rs -sSf | /bin/bash -s -- -y --default-toolchain nightly

Run

$ cd rocket-webapi
$ cargo run


  Configured for development.
    => address: localhost
    => port: 8000
    => log: normal
    => workers: 8
    => secret key: generated
    => limits: forms = 32KiB
    => tls: disabled
  Mounting '/':
    => GET /
    => GET /todos
    => GET /todos/<todoid>
  Rocket has launched from http://localhost:8000

Usage

  • Hello, world!

     http://localhost:8000
    
  • Get all ToDOs

     http://localhost:8000/todos
    
  • Get ToDO by ID

     http://localhost:8000/todos/10
    

Tutorial

Rust

RustCC++10C++MMOC++17Modern CMakeRangeRustC++Rust()C++23SaneRust()

Rocket

RocketRustPythonFlaskTODOWebAPIRocket

Hello Rocket!

Hello, world

  •  $ cargo new rocket-webapi
     $ cd rocket-webapi
    
  • rust-toolchain

     nightly
    
  • Cargo.toml

     [package]
     name = "rocket-jsonapi"
     version = "0.1.0"
     
     [dependencies]
     rocket = "0.4"
     rocket_contrib = { version = "0.4", features = ["json"] }
    
  • src/main.rs

     #![feature(proc_macro_hygiene)]
     #![feature(decl_macro)]
     
     #[macro_use]
     extern crate rocket;
     
     /// GET"Hello, world!"
     #[get("/")]
     fn index() -> &'static str {
         "Hello, world!"
     }
     
     fn main() {
         rocket::ignite()
             .mount("/", routes![index])  // 
             .launch();
     }
    
$ cargo run


  Configured for development.
    => address: localhost
    => port: 8000
    => log: normal
    => workers: 8
    => secret key: generated
    => limits: forms = 32KiB
    => tls: disabled
  Mounting '/':
    => GET /
  Rocket has launched from http://localhost:8000
$ curl http://localhost:8000
Hello, world!

(^o^)

# Rust toolchain
rustup update

ToDOWebAPI

ToDoWebAPI

  • Cargo.toml

     [package]
     name = "rocket-webapi"
     version = "0.1.0"
     
     [dependencies]
     rocket = "0.4"
     rocket_contrib = { version = "0.4", features = ["json"] }
     # serdecrate
     serde = { version = "1.0", features = ["derive"] }
     serde_json = "1.0.0"
    
  • main.rs

     #![feature(proc_macro_hygiene)]
     #![feature(decl_macro)]
     
     #[macro_use]
     extern crate rocket;
     
     mod models;
     mod routes;
     
     // WebAPIURLroutes.rs
     use routes::*;
     
     fn main() {
         rocket::ignite()
             .mount("/", routes![index, todos, new_todo, todo_by_id])
             .launch();
     }
    
  • routes.rs

     // JSON
     use rocket_contrib::json::Json;
     
     use crate::models::ToDo;
     
     #[get("/")]
     pub fn index() -> &'static str {
         "Hello, world!"
     }
     
     /// TODO
     /// JsonResponderimplJSON
     #[get("/todos")]
     pub fn todos() -> Json<Vec<ToDo>> {
         Json(vec![ToDo {
             id: 1,
             title: "Read Rocket tutorial".into(),
             description: "Read https://rocket.rs/guide/quickstart/".into(),
             done: false,
         }])
     }
     
     /// TODO
     /// POST
     #[post("/todos", data = "<todo>")]
     pub fn new_todo(todo: Json<ToDo>) -> String {
         format!("Accepted post request! {:?}", todo.0)
     }
     
     
     /// TODO
     #[get("/todos/<todoid>")]
     pub fn todo_by_id(todoid: u32) -> String {
         let todo = ToDo {
             id: 1,
             title: "Read Rocket tutorial".into(),
             description: "Read https://rocket.rs/guide/quickstart/".into(),
             done: false,
         };
         format!("{:?}", todo)
     }
    
  • models.rs

     use serde::{Deserialize, Serialize};
    
     /// TODOmodels.rs
     #[derive(Debug, Serialize, Deserialize)]
     pub struct ToDo {
         pub id: u32,
         pub title: String,
         pub description: String,
         pub done: bool,
     }
    
$ cargo run

  Configured for development.
    => address: localhost
    => port: 8000
    => log: normal
    => workers: 8
    => secret key: generated
    => limits: forms = 32KiB
    => tls: disabled
  Mounting '/':
    => GET /
    => GET /todos
    => POST /todos
    => GET /todos/<todoid>
  Rocket has launched from http://localhost:8000

curl

$ curl -i http://localhost:8000/todos

HTTP/1.1 200 OK
Content-Type: application/json
Server: Rocket
Content-Length: 111
Date: Wed, 04 Jul 2018 13:44:50 GMT

[{"id":1,"title":"Read Rocket tutorial","description":"Read https://rocket.rs/guide/quickstart/","done":false}]

OK,

POST

$ curl -i -H "Content-Type: application/json" -X POST -d '{"id": 100, "title":"Read this book", "description": "http://shop.oreilly.com/product/0636920040385.do", "done": false}' http://localhost:20000/todos

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Server: Rocket
Content-Length: 142
Date: Thu, 05 Jul 2018 03:55:22 GMT

Accepted post request! ToDo { id: 100, title: "Read this book", description: "http://shop.oreilly.com/product/0636920040385.do", done: false }

POSTOK

Responder

JsonJSONResponderRocketResponderimpl

RocketResponderimplimplResponderimpl

&'static str, &str, String text/plain
NamedFile
Redirect URL
Stream HTTP
Json application/jsonJSON
Template Template
rocket::response::status Accepted203 Accepted
Option Some(T)TResponderNone404 Not Found
Result<T,E> Ok(T)TErr(E)UResponder

3Wrapping ResponderWrapResponder

  • JSON

     fn sample() -> Json<ToDo> {
         Json(ToDo {
             id: 1,
             title: "Read Rocket tutorial".into(),
             description: "Read https://rocket.rs/guide/quickstart/".into(),
             done: false,
         })
     }
    
     $ curl http://localhost:8000/todos
    
     {"id":1,"title":"Read Rocket tutorial","description":"Read https://rocket.rs/guide/quickstart/","done":false}
    
  • Vector

     fn sample() -> Vec<Json<ToDo>> {
     	Json(vec![ToDo {
     	    id: 1,
     	    title: "Read Rocket tutorial".into(),
     	    description: "Read https://rocket.rs/guide/quickstart/".into(),
     	    done: false,
     	}])
     }
    
     $ curl http://localhost:8000/todos
    
     [{"id":1,"title":"Read Rocket tutorial","description":"Read https://rocket.rs/guide/quickstart/","done":false}]
    

JSONArray

  • rocket::response::status::Acceptedwrap
     use rocket::response::status::Accepted;
     fn sample() -> Accepted<Vec<Json<ToDo>>> {
     	Accepted(Some(Json(vec![ToDo {
     		id: 1,
     		title: "Read Rocket tutorial".into(),
     		description: "Read https://rocket.rs/guide/quickstart/".into(),
     		done: false,
     	}])))
     }
    
     $ curl -i http://localhost:8000/todos
     HTTP/1.1 202 Accepted
     Content-Type: application/json
     Server: Rocket
     Content-Length: 111
     Date: Fri, 06 Jul 2018 15:32:19 GMT
    
     [{"id":1,"title":"Read Rocket tutorial","description":"Read https://rocket.rs/guide/quickstart/","done":false}]
    

Status code202 Accepted