Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions responder_test.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
///|
async test "direct string responder sets text content type" {
let app = new()
app.get("/text", _ => "hello")
let response = dispatch_http(app, "GET", "/text", {}, b"")
inspect(response.status_code.to_int(), content="200")
@test.assert_eq(
response.headers.get("Content-Type"),
Some("text/plain; charset=utf-8"),
)
let body : String = response.read_body()
@test.assert_eq(body, "hello")
}

///|
async test "direct json responder sets json content type" {
let app = new()
app.get("/json", _ => ({ "ok": true } : Json))
let response = dispatch_http(app, "GET", "/json", {}, b"")
inspect(response.status_code.to_int(), content="200")
@test.assert_eq(
response.headers.get("Content-Type"),
Some("application/json; charset=utf-8"),
)
let body : Json = response.read_body()
json_inspect(body, content={ "ok": true })
}

///|
async test "direct html responder sets html content type" {
let app = new()
app.get("/html", _ => html("<h1>Hello</h1>"))
let response = dispatch_http(app, "GET", "/html", {}, b"")
inspect(response.status_code.to_int(), content="200")
@test.assert_eq(
response.headers.get("Content-Type"),
Some("text/html; charset=utf-8"),
)
let body : String = response.read_body()
@test.assert_eq(body, "<h1>Hello</h1>")
}

///|
async test "custom status body infers text content type" {
let app = new()
app.get("/bad-request", _ => {
HttpResponse::new(BadRequest).body("Invalid JSON")
})
let response = dispatch_http(app, "GET", "/bad-request", {}, b"")
inspect(response.status_code.to_int(), content="400")
@test.assert_eq(
response.headers.get("Content-Type"),
Some("text/plain; charset=utf-8"),
)
let body : String = response.read_body()
@test.assert_eq(body, "Invalid JSON")
}

///|
async test "custom status html body infers html content type" {
let app = new()
app.get("/not-found", _ => {
HttpResponse::new(NotFound).body(html("<h1>404</h1>"))
})
let response = dispatch_http(app, "GET", "/not-found", {}, b"")
inspect(response.status_code.to_int(), content="404")
@test.assert_eq(
response.headers.get("Content-Type"),
Some("text/html; charset=utf-8"),
)
let body : String = response.read_body()
@test.assert_eq(body, "<h1>404</h1>")
}

///|
async test "json response infers json content type" {
let app = new()
app.get("/created", _ => {
HttpResponse::new(Created).json({ "ok": true })
})
let response = dispatch_http(app, "GET", "/created", {}, b"")
inspect(response.status_code.to_int(), content="201")
@test.assert_eq(
response.headers.get("Content-Type"),
Some("application/json; charset=utf-8"),
)
let body : Json = response.read_body()
json_inspect(body, content={ "ok": true })
}

///|
async test "explicit content type wins over inferred body type" {
let app = new()
app.get("/custom-body", _ => {
HttpResponse::new(
OK,
headers={ "Content-Type": "application/vnd.custom" },
).body("plain text")
})
app.get("/custom-json", _ => {
HttpResponse::new(
OK,
headers={ "Content-Type": "application/vnd.custom+json" },
).json({ "ok": true })
})

let body_response = dispatch_http(app, "GET", "/custom-body", {}, b"")
@test.assert_eq(
body_response.headers.get("Content-Type"),
Some("application/vnd.custom"),
)
let body : String = body_response.read_body()
@test.assert_eq(body, "plain text")

let json_response = dispatch_http(app, "GET", "/custom-json", {}, b"")
@test.assert_eq(
json_response.headers.get("Content-Type"),
Some("application/vnd.custom+json"),
)
let json : Json = json_response.read_body()
json_inspect(json, content={ "ok": true })
}
21 changes: 21 additions & 0 deletions response.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,38 @@ pub fn HttpResponse::new(
}

///|
/// Sets the response body from any `Responder`.
///
/// The body responder's default `Content-Type` is carried into this
/// response only when no explicit `"Content-Type"` header was set on this
/// response. Explicit response headers always take precedence.
///
/// Only the default `Content-Type` is inferred. The responder's status,
/// other headers, cookies, and any other responder effects are not merged,
/// so `self.status_code` is preserved.
pub fn HttpResponse::body(
self : HttpResponse,
body : &Responder,
) -> HttpResponse {
let probe = HttpResponse::new(OK)
body.options(probe)
if probe.headers.get("Content-Type") is Some(content_type) &&
!self.headers.contains("Content-Type") {
self.headers["Content-Type"] = content_type
}
let buf = Buffer()
body.output(buf)
self.raw_body = buf.to_bytes()
self
}

///|
/// Sets a JSON response body.
///
/// Infers `Content-Type: application/json; charset=utf-8` under the same
/// rule as `HttpResponse::body`: an explicit `"Content-Type"` header already
/// present on this response takes precedence, and `self.status_code` is
/// preserved.
pub fn HttpResponse::json(self : HttpResponse, obj : &ToJson) -> HttpResponse {
self.body(obj.to_json())
}
Expand Down
Loading