cors_builder

cors_builder provides an easy way to build and inject your CORS configuration in your server. The package tries to remains as simplest as possible, while guaranteeing type-safety and correctness of the CORS configuration.

Quickstart

Import the cors_builder package, and configure your CORS. Finally, use the correct corresponding middleware for your server, and you’re done!

import cors_builder as cors
import gleam/http
import mist
import wisp.{type Request, type Response}

// Dummy example.
fn cors() {
  cors.new()
  |> cors.allow_origin("http://localhost:3000")
  |> cors.allow_origin("http://localhost:4000")
  |> cors.allow_method(http.Get)
  |> cors.allow_method(http.Post)
}

fn handler(req: Request) -> Response {
  use req <- cors.wisp_middleware(req, cors())
  wisp.ok()
}

fn main() {
  handler
  |> wisp.mist_handler(secret_key)
  |> mist.new()
  |> mist.port(3000)
  |> mist.start_http()
}

Low-level functions

If you’re building your framework or you know what you’re doing, you should take a look at set_cors and set_cors_multiple_origin. They allow to inject the CORS in your response, and it allows you to create your middleware to use with the bare CORS data.

If you’re not building your framework, you should probably heads to wisp to get you started. It’s better to familiarize with the ecosystem before jumping right in your custom code.

Types

CORS builder. Use it in your program to generate the good CORS for your responses.

pub opaque type Cors

Indicates the origin for CORS. Could be any origin (wildcard "*") or a list of domains. In case it’s a list of domains, one domain will be returned every time, and the vary header will be filled with origin. If you only have one domain, the domain will always be filled.

pub opaque type Origin

Functions

pub fn allow_all_origins(cors: Cors) -> Cors

Allow all domains to access your server.

Be extremely careful, you should not use this function in production! Allowing all origins can easily be a huge security flaw! Allow only the origins you need, and use this function only locally, in dev mode.

pub fn allow_credentials(cors: Cors) -> Cors

Allow credentials to be sent in the request. Credentials take form of username and password, stored in cookies most of the time.

Be extremely careful with this header, and consider it with caution, mainly for legacy systems relying on cookies or for systems aware of the danger of cookies, because of CSRF attacks. You probably don’t really need it if you use lustre or any modern framework you’ll find in the gleam ecosystem!

When you can, prefer using some modern system, like OAuth2 or rely on a framework doing the authentication for you. A simple and secured way to authenticate your users is to use the authorization header, with a Bearer token.

pub fn allow_header(cors: Cors, header: String) -> Cors

All header to be sent to the server. You can specify multiple headers to send to your server. In this case, call the function multiple times on Cors data.

fn cors() {
  cors.new()
  |> cors.allow_header("content-type")
  |> cors.allow_header("origin")
}
pub fn allow_method(cors: Cors, method: Method) -> Cors

Allow methods to be used in subsequent CORS requests. You can specify multiple allowed methods. In this case, call the function multiple times on Cors data.

import gleam/http

fn cors() {
  cors.new()
  |> cors.allow_method(http.Get)
  |> cors.allow_method(http.Post)
}
pub fn allow_origin(cors: Cors, origin: String) -> Cors

Allow a specific domain to access your server. The domain must be a valid URI, conformant to RFC 3986. In case it’s not conformant, a warning will be emitted, and Cors won’t be changed. You can specify multiple domains to access your server. In this case, call the function multiple times on Cors data.

fn cors() {
  cors.new()
  |> cors.allow_origin("domain")
  |> cors.allow_origin("domain2")
}
pub fn expose_header(cors: Cors, header: String) -> Cors

Expose headers in the resulting request. You can specify multiple headers to access your server. In this case, call the function multiple times on Cors data.

fn cors() {
  cors.new()
  |> cors.expose_header("content-type")
  |> cors.expose_header("vary")
}
pub fn max_age(cors: Cors, age: Int) -> Cors

Set an amount of milliseconds during which CORS requests can be cached. When using max_age, the browser will issue one request OPTIONS at first, and will reuse the result of that request for the specified amount of time. Once the cache expired, a new OPTIONS request will be made.

pub fn mist_middleware(
  req: Request(Connection),
  cors: Cors,
  handler: fn(Request(Connection)) -> Response(ResponseData),
) -> Response(ResponseData)

Intercepts the request for mist and handles CORS directly without worrying about it. Provide your CORS configuration, and you’re good to go!

pub fn new() -> Cors

Creates an empty CORS object. It will not contains anything by default. If you’re using it directly, no headers will be added to the response.

pub fn set_cors(res: Response(a), cors: Cors) -> Response(a)

Set CORS headers on a response. Should be used in your handler. In case you’re using a framework, it probably already implements it. If you’re using mist or wisp, use the corresponding provided middlewares, (mist_middleware) and (wisp_middleware) and do not use this “low-level” function.

pub fn set_cors_multiple_origin(
  res: Response(a),
  cors: Cors,
  origin: String,
) -> Response(a)

Set CORS headers on a response. Should be used when you have multiple allowed domains. Should be used in your handler. In case you’re using a framework, it probably already implements it. If you’re using mist or wisp, use the corresponding provided middlewares, (mist_middleware) and (wisp_middleware) and do not use this “low-level” function.

pub fn wisp_middleware(
  req: Request(Connection),
  cors: Cors,
  handler: fn(Request(Connection)) -> Response(Body),
) -> Response(Body)

Intercepts the request for wisp and handles CORS directly without worrying about it. Provide your CORS configuration and you’re good to go!

Search Document