Skip to content

Commit

Permalink
Merge pull request #125 from xsnippet/request-id
Browse files Browse the repository at this point in the history
Generate a unique id for each request and return it in the X-Request-Id header
  • Loading branch information
malor committed Mar 13, 2021
2 parents 699d957 + c3e8ba4 commit 9b51584
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 12 deletions.
55 changes: 45 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ rocket = "0.4.5"
rocket_contrib = {version = "0.4.5", features = ["json"]}
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
uuid = { version = "0.8.2", features = ["v4"] }
2 changes: 2 additions & 0 deletions src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::error::Error;

use super::routes;
use super::storage::{SqlStorage, Storage};
use super::web::RequestIdHeader;

#[derive(Debug)]
pub struct Config {
Expand Down Expand Up @@ -49,5 +50,6 @@ pub fn create_app() -> Result<rocket::Rocket, Box<dyn Error>> {
Ok(app
.manage(Config { syntaxes })
.manage(storage)
.attach(RequestIdHeader)
.mount("/v1", routes))
}
2 changes: 2 additions & 0 deletions src/web.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod content;
mod tracing;

pub use content::{Input, NegotiatedContentType, Output};
pub use tracing::{RequestId, RequestIdHeader};
48 changes: 48 additions & 0 deletions src/web/tracing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use rocket::fairing::{Fairing, Info, Kind};
use rocket::request::{self, FromRequest, Request};
use rocket::{Outcome, Response};

/// Unique identifier assigned to a given API request.
pub struct RequestId(pub String);

impl RequestId {
pub fn new() -> Self {
RequestId(uuid::Uuid::new_v4().to_hyphenated().to_string())
}
}

impl Default for RequestId {
fn default() -> Self {
RequestId::new()
}
}

impl<'a, 'r> FromRequest<'a, 'r> for &'a RequestId {
type Error = ();

fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
// on first access, generate a new value and store it in the request cache
Outcome::Success(request.local_cache(RequestId::default))
}
}

/// Rocket fairing that returns the identifier of the API request in the
/// X-Request-Id response header.
pub struct RequestIdHeader;

impl Fairing for RequestIdHeader {
fn info(&self) -> Info {
Info {
name: "X-Request-Id response header",
kind: Kind::Response,
}
}

fn on_response(&self, request: &Request, response: &mut Response) {
if let Some(request_id) = request.guard::<&RequestId>().succeeded() {
response.set_raw_header("X-Request-Id", request_id.0.clone());
} else {
eprintln!("Failed to generate a request id");
}
}
}
13 changes: 13 additions & 0 deletions tests/gabbits/create-snippet-errors.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
common:
- &request_id_regex /^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$/

fixtures:
- XSnippetApi

Expand All @@ -10,6 +13,7 @@ tests:
status: 415
response_headers:
content-type: application/json
x-request-id: *request_id_regex
response_json_paths:
$:
message: "Support media types: application/json"
Expand All @@ -27,6 +31,8 @@ tests:
- spam
- eggs
status: 406
response_headers:
x-request-id: *request_id_regex

- name: create a new snippet (invalid HTTP method)
PUT: /v1/snippets
Expand All @@ -40,6 +46,8 @@ tests:
- spam
- eggs
status: 404
response_headers:
x-request-id: *request_id_regex

- name: create a new snippet (invalid JSON)
POST: /v1/snippets
Expand All @@ -49,6 +57,7 @@ tests:
status: 400
response_headers:
content-type: application/json
x-request-id: *request_id_regex
response_json_paths:
$:
message: "Invalid JSON"
Expand All @@ -67,6 +76,7 @@ tests:
status: 400
response_headers:
content-type: application/json
x-request-id: *request_id_regex
response_json_paths:
$:
message: "`content` - empty values not allowed."
Expand All @@ -85,6 +95,7 @@ tests:
status: 400
response_headers:
content-type: application/json
x-request-id: *request_id_regex
response_json_paths:
$:
message: "`syntax` - unallowed value cpp."
Expand All @@ -101,6 +112,7 @@ tests:
status: 400
response_headers:
content-type: application/json
x-request-id: *request_id_regex
response_json_paths:
$.message: "/invalid type: string \"spam\"/"

Expand All @@ -119,5 +131,6 @@ tests:
status: 400
response_headers:
content-type: application/json
x-request-id: *request_id_regex
response_json_paths:
$.message: "/unknown field `syntax1`/"
12 changes: 11 additions & 1 deletion tests/gabbits/create-snippet.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
common:
- &datetime_regex /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+(\+\d{2}:\d{2})|Z$/
- &slug_regex /^[a-zA-Z0-9]+$/
- &location_regex /^/v1/snippets/[a-zA-Z0-9]+$/
- &request_id_regex /^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$/
- &slug_regex /^[a-zA-Z0-9]+$/

fixtures:
- XSnippetApi
Expand All @@ -22,6 +23,7 @@ tests:
response_headers:
content-type: application/json
location: *location_regex
x-request-id: *request_id_regex
response_json_paths:
$.id: *slug_regex
$.title: Hello, World!
Expand Down Expand Up @@ -49,6 +51,7 @@ tests:
response_headers:
content-type: application/json
location: *location_regex
x-request-id: *request_id_regex
response_json_paths:
$.id: *slug_regex
$.title: Hello, World!
Expand Down Expand Up @@ -76,6 +79,7 @@ tests:
response_headers:
content-type: application/json
location: *location_regex
x-request-id: *request_id_regex
response_json_paths:
$.id: *slug_regex
$.title: Hello, World!
Expand Down Expand Up @@ -103,6 +107,7 @@ tests:
response_headers:
content-type: application/json
location: *location_regex
x-request-id: *request_id_regex
response_json_paths:
$.id: *slug_regex
$.title: Hello, World!
Expand Down Expand Up @@ -130,6 +135,7 @@ tests:
response_headers:
content-type: application/json
location: *location_regex
x-request-id: *request_id_regex
response_json_paths:
$.id: *slug_regex
$.title: Hello, World!
Expand All @@ -153,6 +159,7 @@ tests:
response_headers:
content-type: application/json
location: *location_regex
x-request-id: *request_id_regex
response_json_paths:
$.id: *slug_regex
$.title: Hello, World!
Expand All @@ -176,6 +183,7 @@ tests:
response_headers:
content-type: application/json
location: *location_regex
x-request-id: *request_id_regex
response_json_paths:
$.id: *slug_regex
$.title:
Expand All @@ -201,6 +209,7 @@ tests:
response_headers:
content-type: application/json
location: *location_regex
x-request-id: *request_id_regex
response_json_paths:
$.id: *slug_regex
$.title: Hello, World!
Expand All @@ -222,6 +231,7 @@ tests:
response_headers:
content-type: application/json
location: *location_regex
x-request-id: *request_id_regex
response_json_paths:
$.id: *slug_regex
$.title:
Expand Down

0 comments on commit 9b51584

Please sign in to comment.