wisp
Types
The body of a HTTP response, to be sent to the client.
pub type Body {
Text(StringBuilder)
File(path: String)
Empty
}
Constructors
-
Text(StringBuilder)
A body of unicode text.
The body is represented using a
StringBuilder
. If you have aString
you can use thestring_builder.from_string
function to convert it. -
File(path: String)
A body of the contents of a file.
This will be sent efficiently using the
send_file
function of the underlying HTTP server. The file will not be read into memory so it is safe to send large files this way. -
Empty
An empty body. This may be returned by the
require_*
middleware functions in the event of a failure, invalid request, or other situation in which the request cannot be processed.Your application may wish to use a middleware to provide default responses in place of any with an empty body.
The connection to the client for a HTTP request.
The body of the request can be read from this connection using functions
such as require_multipart_body
.
pub opaque type Connection
Data parsed from form sent in a request’s body.
pub type FormData {
FormData(
values: List(#(String, String)),
files: List(#(String, UploadedFile)),
)
}
Constructors
-
FormData( values: List(#(String, String)), files: List(#(String, UploadedFile)), )
Arguments
-
values
String values of the form’s fields.
-
files
Uploaded files.
-
A convenient alias for a HTTP request with a Wisp connection as the body.
pub type Request =
HttpRequest(Connection)
pub type Security {
PlainText
Signed
}
Constructors
-
PlainText
The value is store as plain text without any additional security. The client will be able to read and modify the value, and create new values.
-
Signed
The value is signed to prevent modification. The client will be able to read the value but not modify it, or create new values.
String values of the form’s fields. Uploaded files.
pub type UploadedFile {
UploadedFile(file_name: String, path: String)
}
Constructors
-
UploadedFile(file_name: String, path: String)
Arguments
-
file_name
The name that was given to the file in the form. This is user input and should not be trusted.
-
path
The location of the file on the server. This is a temporary file and will be deleted when the request has finished being handled.
-
Constants
pub const path_segments: fn(Request(a)) -> List(String) = request.path_segments
Return the non-empty segments of a request path.
Examples
> request.new()
> |> request.set_path("/one/two/three")
> |> wisp.path_segments
["one", "two", "three"]
pub const priv_directory: fn(String) -> Result(String, Nil) = erlang.priv_directory
Returns the path of a package’s priv
directory, where extra non-Gleam
or Erlang files are typically kept.
Returns an error if no package was found with the given name.
Example
> erlang.priv_directory("my_app")
// -> Ok("/some/location/my_app/priv")
pub const set_header: fn(Response(a), String, String) ->
Response(a) = response.set_header
Set a given header to a given value, replacing any existing value.
Examples
> wisp.ok()
> |> wisp.set_header("content-type", "application/json")
Request(200, [#("content-type", "application/json")], Empty)
Functions
pub fn accepted() -> Response(Body)
Create an empty response with status code 202: Accepted.
Examples
created()
// -> Response(202, [], Empty)
pub fn bad_request() -> Response(Body)
Create an empty response with status code 400: Bad request.
Examples
bad_request()
// -> Response(400, [], Empty)
pub fn configure_logger() -> Nil
Configure the Erlang logger, setting the minimum log level to info
, to be
called when your application starts.
You may wish to use an alternative for this such as one provided by a more sophisticated logging library.
In future this function may be extended to change the output format.
pub fn create_canned_connection(
body: BitArray,
secret_key_base: String,
) -> Connection
Create a connection which will return the given body when read.
This function is intended for use in tests, though you probably want the
wisp/testing
module instead.
pub fn created() -> Response(Body)
Create an empty response with status code 201: Created.
Examples
created()
// -> Response(201, [], Empty)
pub fn delete_temporary_files(
request: Request(Connection),
) -> Result(Nil, FileError)
Delete any temporary files created for the given request.
If you are using the mist_handler
function or another compliant web server
adapter then this file will be deleted for you when the request is complete.
Otherwise you will need to call this function yourself.
pub fn entity_too_large() -> Response(Body)
Create an empty response with status code 413: Entity too large.
Examples
entity_too_large()
// -> Response(413, [], Empty)
pub fn escape_html(content: String) -> String
Escape a string so that it can be safely included in a HTML document.
Any content provided by the user should be escaped before being included in a HTML document to prevent cross-site scripting attacks.
Examples
escape_html("<h1>Hello, Joe!</h1>")
// -> "<h1>Hello, Joe!</h1>"
pub fn get_cookie(
request: Request(Connection),
name: String,
security: Security,
) -> Result(String, Nil)
Get a cookie from the request.
If a cookie is missing, found to be malformed, or the signature is invalid
for a signed cookie, then Error(Nil)
is returned.
wisp.get_cookie(request, "group")
// -> Ok("A")
pub fn get_max_body_size(request: Request(Connection)) -> Int
Get the maximum permitted size of a request body of the request in bytes.
pub fn get_max_files_size(request: Request(Connection)) -> Int
Get the maximum permitted total size of a files uploaded by a request in bytes.
pub fn get_query(
request: Request(Connection),
) -> List(#(String, String))
Parse the query parameters of a request into a list of key-value pairs. The
key_find
function in the gleam/list
stdlib module may be useful for
finding values in the list.
Query parameter names do not have to be unique and so may appear multiple times in the list.
pub fn get_read_chunk_size(request: Request(Connection)) -> Int
Get the size limit for each chunk of the request body when read from the client.
pub fn get_secret_key_base(
request: Request(Connection),
) -> String
Get the secret key base used to sign cookies and other sensitive data.
pub fn handle_head(
req: Request(Connection),
next handler: fn(Request(Connection)) -> Response(Body),
) -> Response(Body)
A middleware function that converts HEAD
requests to GET
requests,
handles the request, and then discards the response body. This is useful so
that your application can handle HEAD
requests without having to implement
handlers for them.
The x-original-method
header is set to "HEAD"
for requests that were
originally HEAD
requests.
Examples
fn handle_request(req: Request) -> Response {
use req <- wisp.handle_head(req)
// ...
}
pub fn html_body(
response: Response(Body),
html: StringBuilder,
) -> Response(Body)
Set the body of a response to a given HTML document, and set the
content-type
header to text/html
.
The body is expected to be valid HTML, though this is not validated.
Examples
let body = string_builder.from_string("<h1>Hello, Joe!</h1>")
response(201)
|> html_body(body)
// -> Response(201, [#("content-type", "text/html")], Text(body))
pub fn html_response(
html: StringBuilder,
status: Int,
) -> Response(Body)
Create a HTML response.
The body is expected to be valid HTML, though this is not validated.
The content-type
header will be set to text/html
.
Examples
let body = string_builder.from_string("<h1>Hello, Joe!</h1>")
html_response(body, 200)
// -> Response(200, [#("content-type", "text/html")], Text(body))
pub fn internal_server_error() -> Response(Body)
Create an empty response with status code 500: Internal server error.
Examples
internal_server_error()
// -> Response(500, [], Empty)
pub fn json_body(
response: Response(Body),
json: StringBuilder,
) -> Response(Body)
Set the body of a response to a given JSON document, and set the
content-type
header to application/json
.
The body is expected to be valid JSON, though this is not validated.
Examples
let body = string_builder.from_string("{\"name\": \"Joe\"}")
response(201)
|> json_body(body)
// -> Response(201, [#("content-type", "application/json")], Text(body))
pub fn json_response(
json: StringBuilder,
status: Int,
) -> Response(Body)
Create a JSON response.
The body is expected to be valid JSON, though this is not validated.
The content-type
header will be set to application/json
.
Examples
let body = string_builder.from_string("{\"name\": \"Joe\"}")
html_response(body, 200)
// -> Response(200, [#("content-type", "application/json")], Text(body))
pub fn log_alert(message: String) -> Nil
Log a message to the Erlang logger with the level of alert
.
See the Erlang logger documentation for more information.
pub fn log_critical(message: String) -> Nil
Log a message to the Erlang logger with the level of critical
.
See the Erlang logger documentation for more information.
pub fn log_debug(message: String) -> Nil
Log a message to the Erlang logger with the level of debug
.
See the Erlang logger documentation for more information.
pub fn log_emergency(message: String) -> Nil
Log a message to the Erlang logger with the level of emergency
.
See the Erlang logger documentation for more information.
pub fn log_error(message: String) -> Nil
Log a message to the Erlang logger with the level of error
.
See the Erlang logger documentation for more information.
pub fn log_info(message: String) -> Nil
Log a message to the Erlang logger with the level of info
.
See the Erlang logger documentation for more information.
pub fn log_notice(message: String) -> Nil
Log a message to the Erlang logger with the level of notice
.
See the Erlang logger documentation for more information.
pub fn log_request(
req: Request(Connection),
handler: fn() -> Response(Body),
) -> Response(Body)
A middleware function that logs details about the request and response.
The format used logged by this middleware may change in future versions of Wisp.
Examples
fn handle_request(req: Request) -> Response {
use <- wisp.log_request(req)
// ...
}
pub fn log_warning(message: String) -> Nil
Log a message to the Erlang logger with the level of warning
.
See the Erlang logger documentation for more information.
pub fn method_not_allowed(
allowed methods: List(Method),
) -> Response(Body)
Create an empty response with status code 405: Method Not Allowed. Use this when a request does not have an appropriate method to be handled.
The allow
header will be set to a comma separated list of the permitted
methods.
Examples
method_not_allowed(allowed: [Get, Post])
// -> Response(405, [#("allow", "GET, POST")], Empty)
pub fn method_override(request: Request(a)) -> Request(a)
This function overrides an incoming POST request with a method given in
the request’s _method
query paramerter. This is useful as web browsers
typically only support GET and POST requests, but our application may
expect other HTTP methods that are more semantically correct.
The methods PUT, PATCH, and DELETE are accepted for overriding, all others are ignored.
The _method
query paramerter can be specified in a HTML form like so:
Examples
fn handle_request(request: Request) -> Response {
let request = wisp.method_override(request)
// The method has now been overridden if appropriate
}
pub fn mist_handler(
handler: fn(Request(Connection)) -> Response(Body),
secret_key_base: String,
) -> fn(Request(mist/internal/http.Connection)) ->
Response(ResponseData)
Convert a Wisp request handler into a function that can be run with the Mist web server.
Examples
pub fn main() {
let secret_key_base = "..."
let assert Ok(_) =
handle_request
|> wisp.mist_handler(secret_key_base)
|> mist.new
|> mist.port(8000)
|> mist.start_http
process.sleep_forever()
}
pub fn moved_permanently(to url: String) -> Response(Body)
Create an empty response with status code 308: Moved Permanently, and the
location
header set to the given URL. Used to redirect the client to
another page.
This redirect is permanent and the client is expected to cache the new location, using it for future requests.
Examples
moved_permanently(to: "https://example.com")
// -> Response(308, [#("location", "https://example.com")], Empty)
pub fn new_temporary_file(
request: Request(Connection),
) -> Result(String, FileError)
Create a new temporary directory for the given request.
If you are using the mist_handler
function or another compliant web server
adapter then this file will be deleted for you when the request is complete.
Otherwise you will need to call the delete_temporary_files
function
yourself.
pub fn no_content() -> Response(Body)
Create an empty response with status code 204: No content.
Examples
no_content()
// -> Response(204, [], Empty)
pub fn not_found() -> Response(Body)
Create an empty response with status code 404: No content.
Examples
not_found()
// -> Response(404, [], Empty)
pub fn ok() -> Response(Body)
Create an empty response with status code 200: OK.
Examples
ok()
// -> Response(200, [], Empty)
pub fn random_string(length: Int) -> String
Generate a random string of the given length.
pub fn read_body_to_bitstring(
request: Request(Connection),
) -> Result(BitArray, Nil)
Read the entire body of the request as a bit string.
You may instead wish to use the require_bit_array_body
or the
require_string_body
middleware functions instead.
This function does not cache the body in any way, so if you call this function (or any other body reading function) more than once it may hang or return an incorrect value, depending on the underlying web server. It is the responsibility of the caller to cache the body if it is needed multiple times.
If the body is larger than the max_body_size
limit then an empty response
with status code 413: Entity too large will be returned to the client.
pub fn redirect(to url: String) -> Response(Body)
Create an empty response with status code 303: See Other, and the location
header set to the given URL. Used to redirect the client to another page.
Examples
redirect(to: "https://example.com")
// -> Response(303, [#("location", "https://example.com")], Empty)
pub fn require_bit_array_body(
request: Request(Connection),
next: fn(BitArray) -> Response(Body),
) -> Response(Body)
A middleware function which reads the entire body of the request as a bit string.
This function does not cache the body in any way, so if you call this function (or any other body reading function) more than once it may hang or return an incorrect value, depending on the underlying web server. It is the responsibility of the caller to cache the body if it is needed multiple times.
If the body is larger than the max_body_size
limit then an empty response
with status code 413: Entity too large will be returned to the client.
Examples
fn handle_request(request: Request) -> Response {
use body <- wisp.require_string_body(request)
// ...
}
pub fn require_content_type(
request: Request(Connection),
expected: String,
next: fn() -> Response(Body),
) -> Response(Body)
This middleware function ensures that the request has a value for the
content-type
header, returning an empty response with status code 415:
Unsupported media type if the header is not the expected value
Examples
fn handle_request(request: Request) -> Response {
use <- wisp.require_content_type(request, "application/json")
// ...
}
pub fn require_form(
request: Request(Connection),
next: fn(FormData) -> Response(Body),
) -> Response(Body)
A middleware which extracts form data from the body of a request that is
encoded as either application/x-www-form-urlencoded
or
multipart/form-data
.
Extracted fields are sorted into alphabetical order by key, so if you wish to use pattern matching the order can be relied upon.
fn handle_request(request: Request) -> Response {
use form <- wisp.require_form(request)
case form.values {
[#("password", pass), #("username", username)] -> // ...
_ -> // ...
}
}
The set_max_body_size
, set_max_files_size
, and set_read_chunk_size
can
be used to configure the reading of the request body.
Any file uploads will streamed into temporary files on disc. These files are automatically deleted when the request handler returns, so if you wish to use them after the request has completed you will need to move them to a new location.
If the request does not have a recognised content-type
header then an
empty response with status code 415: Unsupported media type will be returned
to the client.
If the request body is larger than the max_body_size
or max_files_size
limits then an empty response with status code 413: Entity too large will be
returned to the client.
If the body cannot be parsed successfully then an empty response with status code 400: Bad request will be returned to the client.
pub fn require_json(
request: Request(Connection),
next: fn(Dynamic) -> Response(Body),
) -> Response(Body)
A middleware which extracts JSON from the body of a request.
fn handle_request(request: Request) -> Response {
use json <- wisp.require_json(request)
// decode and use JSON here...
}
The set_max_body_size
and set_read_chunk_size
can be used to configure
the reading of the request body.
If the request does not have the content-type
set to application/json
an
empty response with status code 415: Unsupported media type will be returned
to the client.
If the request body is larger than the max_body_size
or max_files_size
limits then an empty response with status code 413: Entity too large will be
returned to the client.
If the body cannot be parsed successfully then an empty response with status code 400: Bad request will be returned to the client.
pub fn require_method(
request: Request(a),
method: Method,
next: fn() -> Response(Body),
) -> Response(Body)
This middleware function ensures that the request has a specific HTTP method, returning an empty response with status code 405: Method not allowed if the method is not correct.
Examples
fn handle_request(request: Request) -> Response {
use <- wisp.require_method(request, http.Patch)
// ...
}
pub fn require_string_body(
request: Request(Connection),
next: fn(String) -> Response(Body),
) -> Response(Body)
A middleware function which reads the entire body of the request as a string.
This function does not cache the body in any way, so if you call this function (or any other body reading function) more than once it may hang or return an incorrect value, depending on the underlying web server. It is the responsibility of the caller to cache the body if it is needed multiple times.
If the body is larger than the max_body_size
limit then an empty response
with status code 413: Entity too large will be returned to the client.
If the body is found not to be valid UTF-8 then an empty response with status code 400: Bad request will be returned to the client.
Examples
fn handle_request(request: Request) -> Response {
use body <- wisp.require_string_body(request)
// ...
}
pub fn rescue_crashes(
handler: fn() -> Response(Body),
) -> Response(Body)
A middleware function that rescues crashes and returns an empty response with status code 500: Internal server error.
Examples
fn handle_request(req: Request) -> Response {
use <- wisp.rescue_crashes
// ...
}
pub fn response(status: Int) -> Response(Body)
Create an empty response with the given status code.
Examples
response(200)
// -> Response(200, [], Empty)
pub fn serve_static(
req: Request(Connection),
under prefix: String,
from directory: String,
next handler: fn() -> Response(Body),
) -> Response(Body)
A middleware function that serves files from a directory, along with a
suitable content-type
header for known file extensions.
Files are sent using the File
response body type, so they will be sent
directly to the client from the disc, without being read into memory.
The under
parameter is the request path prefix that must match for the
file to be served.
under | from | request.path | file |
---|---|---|---|
/static | /data | /static/file.txt | /data/file.txt |
`` | /data | /static/file.txt | /data/static/file.txt |
/static | `` | /static/file.txt | file.txt |
This middleware will discard any ..
path segments in the request path to
prevent the client from accessing files outside of the directory. It is
advised not to serve a directory that contains your source code, application
configuration, database, or other private files.
Examples
fn handle_request(req: Request) -> Response {
use <- wisp.serve_static(req, under: "/static", from: "/public")
// ...
}
Typically you static assets may be kept in your project in a directory
called priv
. The priv_directory
function can be used to get a path to
this directory.
fn handle_request(req: Request) -> Response {
let assert Ok(priv) = priv_directory("my_application")
use <- wisp.serve_static(req, under: "/static", from: priv)
// ...
}
pub fn set_body(
response: Response(Body),
body: Body,
) -> Response(Body)
Set the body of a response.
Examples
response(200)
|> set_body(File("/tmp/myfile.txt"))
// -> Response(200, [], File("/tmp/myfile.txt"))
pub fn set_cookie(
response response: Response(Body),
request request: Request(Connection),
name name: String,
value value: String,
security security: Security,
max_age max_age: Int,
) -> Response(Body)
Set a cookie on the response. After max_age
seconds the cookie will be
expired by the client.
This function will sign the value if the security
parameter is set to
Signed
, making it so the cookie cannot be tampered with by the client.
Values are base64 encoded so they can contain any characters you want, even if they would not be permitted directly in a cookie.
Cookies are set using gleam_http
’s default attributes for HTTPS. If you
wish for more control over the cookie attributes then you may want to use
the gleam/http/cookie
module from the gleam_http
package instead of this
function. Be sure to sign and escape the cookie value as needed.
Examples
Setting a plain text cookie that the client can read and modify:
wisp.ok()
|> wisp.set_cookie("id", "123", wisp.PlainText, 60 * 60)
Setting a signed cookie that the client can read but not modify:
wisp.ok()
|> wisp.set_cookie("id", value, wisp.Signed, 60 * 60)
pub fn set_max_body_size(
request: Request(Connection),
size: Int,
) -> Request(Connection)
Set the maximum permitted size of a request body of the request in bytes.
If a body is larger than this size attempting to read the body will result in a response with status code 413: Entity too large will be returned to the client.
This limit only applies for headers and bodies that get read into memory.
Part of a multipart body that contain files and so are streamed to disc
instead use the max_files_size
limit.
pub fn set_max_files_size(
request: Request(Connection),
size: Int,
) -> Request(Connection)
Set the maximum permitted size of all files uploaded by a request, in bytes.
If a request contains fails which are larger in total than this size then attempting to read the body will result in a response with status code 413: Entity too large will be returned to the client.
This limit only applies for files in a multipart body that get streamed to
disc. For headers and other content that gets read into memory use the
max_files_size
limit.
pub fn set_read_chunk_size(
request: Request(Connection),
size: Int,
) -> Request(Connection)
The the size limit for each chunk of the request body when read from the client.
This value is passed to the underlying web server when reading the body and the exact size of chunks read depends on the server implementation. It most likely will read chunks smaller than this size if not yet enough data has been received from the client.
pub fn set_secret_key_base(
request: Request(Connection),
key: String,
) -> Request(Connection)
Set the secret key base used to sign cookies and other sensitive data.
This key must be at least 64 bytes long and should be kept secret. Anyone with this secret will be able to manipulate signed cookies and other sensitive data.
Panics
This function will panic if the key is less than 64 bytes long.
pub fn sign_message(
request: Request(Connection),
message: BitArray,
algorithm: HashAlgorithm,
) -> String
Sign a message which can later be verified using the verify_signed_message
function to detect if the message has been tampered with.
Signed messages are not encrypted and can be read by anyone. They are not suitable for storing sensitive information.
This function uses the secret key base from the request. If the secret changes then the signature will no longer be verifiable.
pub fn string_body(
response: Response(Body),
content: String,
) -> Response(Body)
Set the body of a response to a given string builder.
You likely want to also set the request content-type
header to an
appropriate value for the format of the content.
Examples
let body =
response(201)
|> string_builder_body("Hello, Joe!")
// -> Response(
// 201,
// [],
// Text(string_builder.from_string("Hello, Joe"))
// )
pub fn string_builder_body(
response: Response(Body),
content: StringBuilder,
) -> Response(Body)
Set the body of a response to a given string builder.
You likely want to also set the request content-type
header to an
appropriate value for the format of the content.
Examples
let body = string_builder.from_string("Hello, Joe!")
response(201)
|> string_builder_body(body)
// -> Response(201, [], Text(body))
pub fn unprocessable_entity() -> Response(Body)
Create an empty response with status code 422: Unprocessable entity.
Examples
unprocessable_entity()
// -> Response(422, [], Empty)
pub fn unsupported_media_type(
accept acceptable: List(String),
) -> Response(Body)
Create an empty response with status code 415: Unsupported media type.
The allow
header will be set to a comma separated list of the permitted
content-types.
Examples
unsupported_media_type(accept: ["application/json", "text/plain"])
// -> Response(415, [#("allow", "application/json, text/plain")], Empty)
pub fn verify_signed_message(
request: Request(Connection),
message: String,
) -> Result(BitArray, Nil)
Verify a signed message which was signed using the sign_message
function.
Returns the content of the message if the signature is valid, otherwise returns an error.
This function uses the secret key base from the request. If the secret changes then the signature will no longer be verifiable.