std.net.http.test.RequestBuilder
type pub inline RequestBuilderA type for building a std.net.http.server.Request to use for testing an HTTP
server.
Using a RequestBuilder it's possible to test a type that implements
std.net.http.server.Handle without the need for running an actual HTTP
server and sending actual HTTP requests.
Default values
A RequestBuilder uses the following default headers:
Host: localhostUser-Agent: testConnection: close
For the generated request the source address (Request.address) is set to the
address 192.0.2.0:80.
The HTTP version is always set to HTTP 1.1 and can't be changed.
Examples
import std.net.http (Header, Status)
import std.net.http.server (Handle, Request, Response)
import std.net.http.test (RequestBuilder)
import std.test (Tests)
type Handler {}
impl Handle for Handler {
fn pub mut handle(request: mut Request) -> Response {
Response.new.string(request.data.uri.to_string)
}
}
type async Main {
fn async main {
let tests = Tests.new
tests.test('Example test', fn (t) {
let handler = Handler()
let resp = RequestBuilder
.post('/')
.header(Header.host, 'foo')
.query('key', 'value')
.string('hello')
.send(handler)
let body = ByteArray.new
t.equal(resp.status, Status.ok)
t.true(resp.body.reader.read_all(body).ok?)
t.equal(body.to_string, '/?key=value')
})
tests.run
}
}
Fields
headers
let pub @headers: HeaderMapThe request headers.
query
let pub @query: ValuesThe request query string parameters.
Static methods
delete
Show source codeHide source code
fn pub static delete(path: String) -> Self {
new(Method.Delete, path)
}fn pub static delete(path: String) -> RequestBuilderReturns a builder for a DELETE request.
Refer to the documentation of RequestBuilder.new for more details.
get
Show source codeHide source code
fn pub static get(path: String) -> Self {
new(Method.Get, path)
}fn pub static get(path: String) -> RequestBuilderReturns a builder for a GET request.
Refer to the documentation of RequestBuilder.new for more details.
head
Show source codeHide source code
fn pub static head(path: String) -> Self {
new(Method.Head, path)
}fn pub static head(path: String) -> RequestBuilderReturns a builder for a HEAD request.
Refer to the documentation of RequestBuilder.new for more details.
new
Show source codeHide source code
fn pub static new(method: Method, path: String) -> Self {
let headers = HeaderMap.new
# These default headers are added because either they're required (the Host
# header) or probably expected to be present in a real request.
headers.set(Header.host, 'localhost')
headers.set(Header.user_agent, 'test')
headers.set(Header.connection, 'close')
let uri = Uri.new
uri.path = Path.new(path).or_panic_with('the request path is invalid')
Self(
method: method,
uri: uri,
headers: headers,
query: Values.new,
body: Body.None,
)
}fn pub static new(method: Method, path: String) -> RequestBuilderReturns a new request builder using the given method and request path.
Panics
This method panics if the path argument is not a valid path (i.e. it
contains characters that must be percent encoded but aren't).
post
Show source codeHide source code
fn pub static post(path: String) -> Self {
new(Method.Post, path)
}fn pub static post(path: String) -> RequestBuilderReturns a builder for a POST request.
Refer to the documentation of RequestBuilder.new for more details.
put
Show source codeHide source code
fn pub static put(path: String) -> Self {
new(Method.Put, path)
}fn pub static put(path: String) -> RequestBuilderReturns a builder for a PUT request.
Refer to the documentation of RequestBuilder.new for more details.
Instance methods
bytes
Show source codeHide source code
fn pub move bytes(body: ByteArray) -> Self {
@body = Body.Bytes(body)
self
}fn pub move bytes(body: ByteArray) -> RequestBuilderSets the request body to the given ByteArray.
Examples
import std.net.http (Status)
import std.net.http.server (Handle, Request, Response)
import std.net.http.test (RequestBuilder)
import std.test (Tests)
type Handler {}
impl Handle for Handler {
fn pub mut handle(request: mut Request) -> Response {
let body = ByteArray.new
let _ = request.body.read_all(body).or_panic
Response.new.bytes(body)
}
}
type async Main {
fn async main {
let tests = Tests.new
tests.test('Example test', fn (t) {
let handler = Handler()
let resp = RequestBuilder
.post('/')
.bytes('foo'.to_byte_array)
.send(handler)
let body = ByteArray.new
t.equal(resp.status, Status.ok)
t.true(resp.body.reader.read_all(body).ok?)
t.equal(body.to_string, 'foo')
})
tests.run
}
}
header
Show source codeHide source code
fn pub move header(header: Header, value: String) -> Self {
@headers.add(header, value)
self
}fn pub move header(header: Header, value: String) -> RequestBuilderAdds a header and its value to the set of request headers.
If the header is already assigned a value, the value is appended to the list of expected values.
Examples
import std.net.http (Header, Status)
import std.net.http.server (Handle, Request, Response)
import std.net.http.test (RequestBuilder)
import std.test (Tests)
type Handler {}
impl Handle for Handler {
fn pub mut handle(request: mut Request) -> Response {
Response.new.string(request.headers.get(Header.accept).or('missing header'))
}
}
type async Main {
fn async main {
let tests = Tests.new
tests.test('Example test', fn (t) {
let handler = Handler()
let resp = RequestBuilder
.get('/')
.header(Header.accept, 'text/plain')
.send(handler)
let body = ByteArray.new
t.equal(resp.status, Status.ok)
t.true(resp.body.reader.read_all(body).ok?)
t.equal(body.to_string, 'text/plain')
})
tests.run
}
}
multipart_form
Show source codeHide source code
fn pub move multipart_form(
body: fn (mut multipart.Form[mut ByteArray, IoError]),
) -> Self {
let (header, buf) = multipart_form_data(body)
header(Header.content_type, header).bytes(buf)
}fn pub move multipart_form(body: fn (mut Form[mut ByteArray, Error])) -> RequestBuilderTurns self into a multipart form request.
Examples
import std.net.http (Status)
import std.net.http.server (Handle, Request, Response)
import std.net.http.test (RequestBuilder)
import std.test (Tests)
type Handler {}
impl Handle for Handler {
fn pub mut handle(request: mut Request) -> Response {
let pairs = []
let buf = ByteArray.new
for res in request.multipart_form.or_panic {
let Ok(res) = res else next
let _ = res.read_all(buf).or_panic
pairs.push('${res.name}=${buf}')
buf.clear
}
Response.new.string(String.join(pairs.into_iter, '&'))
}
}
type async Main {
fn async main {
let tests = Tests.new
tests.test('Example test', fn (t) {
let handler = Handler()
let resp = RequestBuilder
.post('/')
.multipart_form(fn (f) {
let _ = f.field('name').text('Alice')
let _ = f.field('age').text('42')
})
.send(handler)
let body = ByteArray.new
t.equal(resp.status, Status.ok)
t.true(resp.body.reader.read_all(body).ok?)
t.equal(body.to_string, 'name=Alice&age=42')
})
tests.run
}
}
query
Show source codeHide source code
fn pub move query(key: String, value: String) -> Self {
@query.add(key, value)
self
}fn pub move query(key: String, value: String) -> RequestBuilderAdds a query string parameter and its value to the set of request query string parameters.
If the parameter is already assigned a value, the value is appended to the list of expected values.
Examples
import std.net.http (Status)
import std.net.http.server (Handle, Request, Response)
import std.net.http.test (RequestBuilder)
import std.test (Tests)
type Handler {}
impl Handle for Handler {
fn pub mut handle(request: mut Request) -> Response {
Response.new.string(request.data.uri.to_string)
}
}
type async Main {
fn async main {
let tests = Tests.new
tests.test('Example test', fn (t) {
let handler = Handler()
let resp = RequestBuilder
.get('/')
.query('key', 'value')
.send(handler)
let body = ByteArray.new
t.equal(resp.status, Status.ok)
t.true(resp.body.reader.read_all(body).ok?)
t.equal(body.to_string, '/?key=value')
})
tests.run
}
}
send
Show source codeHide source code
fn pub move send[H: mut + Handle](handler: mut H) -> Response {
@uri.query = @query.to_query
let addr = Address.Ip(
SocketAddress(ip: IpAddress.v4(192, 0, 2, 0), port: 80),
)
let body = match @body {
case None -> {
RawBody.bounded(HttpReader.new(Buffer.new('')), size: 0, limit: 0)
}
case String(v) -> {
RawBody.bounded(
HttpReader.new(Buffer.new(v)),
size: v.size,
limit: v.size,
)
}
case Bytes(v) -> {
let len = v.size
RawBody.bounded(HttpReader.new(Buffer.new(v)), size: len, limit: len)
}
}
let rng = Random.new
let req = Request.new(
addr,
RawRequest(
method: @method,
uri: @uri,
version: Version(1, 1),
headers: @headers,
body: body,
),
Limits.new,
rng,
)
handler.handle(req)
}fn pub move send[H: mut + Handle](handler: mut H: mut) -> ResponseConverts self into a request and sends it to the given request handler.
The return value is the Response returned by the handler.
Examples
import std.net.http (Status)
import std.net.http.server (Handle, Request, Response)
import std.net.http.test (RequestBuilder)
import std.test (Tests)
type Handler {}
impl Handle for Handler {
fn pub mut handle(request: mut Request) -> Response {
Response.new
}
}
type async Main {
fn async main {
let tests = Tests.new
tests.test('Example test', fn (t) {
let handler = Handler()
let resp = RequestBuilder.get('/').send(handler)
t.equal(resp.status, Status.ok)
})
tests.run
}
}
string
Show source codeHide source code
fn pub move string(body: String) -> Self {
@body = Body.String(body)
self
}fn pub move string(body: String) -> RequestBuilderSets the request body to the given String.
Examples
import std.net.http (Status)
import std.net.http.server (Handle, Request, Response)
import std.net.http.test (RequestBuilder)
import std.test (Tests)
type Handler {}
impl Handle for Handler {
fn pub mut handle(request: mut Request) -> Response {
let body = ByteArray.new
let _ = request.body.read_all(body).or_panic
Response.new.bytes(body)
}
}
type async Main {
fn async main {
let tests = Tests.new
tests.test('Example test', fn (t) {
let handler = Handler()
let resp = RequestBuilder.post('/').string('foo').send(handler)
let body = ByteArray.new
t.equal(resp.status, Status.ok)
t.true(resp.body.reader.read_all(body).ok?)
t.equal(body.to_string, 'foo')
})
tests.run
}
}
url_encoded_form
Show source codeHide source code
fn pub move url_encoded_form(body: fn (mut Values)) -> Self {
header(Header.content_type, URL_FORM).string(url_encoded_form_data(body))
}fn pub move url_encoded_form(body: fn (mut Values)) -> RequestBuilderTurns self into a URL encoded form request.
Examples
import std.net.http (Status)
import std.net.http.server (Handle, Request, Response)
import std.net.http.test (RequestBuilder)
import std.test (Tests)
type Handler {}
impl Handle for Handler {
fn pub mut handle(request: mut Request) -> Response {
let body = ByteArray.new
let _ = request.body.read_all(body).or_panic
Response.new.bytes(body)
}
}
type async Main {
fn async main {
let tests = Tests.new
tests.test('Example test', fn (t) {
let handler = Handler()
let resp = RequestBuilder
.post('/')
.url_encoded_form(fn (f) {
f.add('name', 'Alice')
f.add('age', '42')
})
.send(handler)
let body = ByteArray.new
t.equal(resp.status, Status.ok)
t.true(resp.body.reader.read_all(body).ok?)
t.equal(body.to_string, 'name=Alice&age=42')
})
tests.run
}
}