Search results

There are no results.

std.net.http.test.RequestBuilder

type pub inline RequestBuilder

A 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: localhost
  • User-Agent: test
  • Connection: 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: HeaderMap

The request headers.

query

let pub @query: Values

The request query string parameters.

Static methods

delete

Show source code
Hide source code
fn pub static delete(path: String) -> Self {
  new(Method.Delete, path)
}
fn pub static delete(path: String) -> RequestBuilder

Returns a builder for a DELETE request.

Refer to the documentation of RequestBuilder.new for more details.

get

Show source code
Hide source code
fn pub static get(path: String) -> Self {
  new(Method.Get, path)
}
fn pub static get(path: String) -> RequestBuilder

Returns a builder for a GET request.

Refer to the documentation of RequestBuilder.new for more details.

head

Show source code
Hide source code
fn pub static head(path: String) -> Self {
  new(Method.Head, path)
}
fn pub static head(path: String) -> RequestBuilder

Returns a builder for a HEAD request.

Refer to the documentation of RequestBuilder.new for more details.

new

Show source code
Hide 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) -> RequestBuilder

Returns 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 code
Hide source code
fn pub static post(path: String) -> Self {
  new(Method.Post, path)
}
fn pub static post(path: String) -> RequestBuilder

Returns a builder for a POST request.

Refer to the documentation of RequestBuilder.new for more details.

put

Show source code
Hide source code
fn pub static put(path: String) -> Self {
  new(Method.Put, path)
}
fn pub static put(path: String) -> RequestBuilder

Returns a builder for a PUT request.

Refer to the documentation of RequestBuilder.new for more details.

Instance methods

bytes

Show source code
Hide source code
fn pub move bytes(body: ByteArray) -> Self {
  @body = Body.Bytes(body)
  self
}
fn pub move bytes(body: ByteArray) -> RequestBuilder

Sets 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 code
Hide source code
fn pub move header(header: Header, value: String) -> Self {
  @headers.add(header, value)
  self
}
fn pub move header(header: Header, value: String) -> RequestBuilder

Adds 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 code
Hide 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])) -> RequestBuilder

Turns 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 code
Hide source code
fn pub move query(key: String, value: String) -> Self {
  @query.add(key, value)
  self
}
fn pub move query(key: String, value: String) -> RequestBuilder

Adds 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 code
Hide 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) -> Response

Converts 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 code
Hide source code
fn pub move string(body: String) -> Self {
  @body = Body.String(body)
  self
}
fn pub move string(body: String) -> RequestBuilder

Sets 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 code
Hide 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)) -> RequestBuilder

Turns 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
  }
}