dream/servers/mist/server

Your Dream app’s entry point

This module is where your web application starts. It provides a builder pattern for configuring and starting a Dream server using Mist (the BEAM’s HTTP server).

Quick Start

import dream/servers/mist/server
import dream/servers/mist/server.{listen, router}

pub fn main() {
  server.new()
  |> router(create_router())
  |> listen(3000)
}

The builder pattern lets you configure your server step by step. Start with new(), add your router, and optionally set custom context and services before calling listen().

Custom Context and Services

By default, Dream uses EmptyContext (no per-request data) and EmptyServices (no shared dependencies). For most production apps, you’ll want to define your own types:

import dream/servers/mist/server
import dream/servers/mist/server.{context, listen, router, services}
import gleam/option.{None}

pub type MyContext {
  MyContext(request_id: String, user: option.Option(User), session: Session)
}

server.new()
|> context(MyContext(request_id: "", user: None, session: empty_session()))
|> services(initialize_services())
|> router(create_router())
|> listen(3000)

The type system ensures your controllers receive the correct context type.

Types

Handle to a running server process

Returned by listen_with_handle() and used by stop() to stop the server.

pub opaque type ServerHandle

Values

pub fn bind(
  dream_instance: dream.Dream(
    mist.Builder(mist.Connection, mist.ResponseData),
    context,
    services,
  ),
  interface: String,
) -> dream.Dream(
  mist.Builder(mist.Connection, mist.ResponseData),
  context,
  services,
)

Set the network interface to bind to

Defaults to binding to all interfaces. Use “localhost” or “127.0.0.1” to only accept local connections, or “0.0.0.0” to accept connections from any network interface.

Example

import dream/servers/mist/server
import dream/servers/mist/server.{bind, listen, router, services}

// Only accept local connections
server.new()
|> services(my_services)
|> router(my_router)
|> bind("localhost")
|> listen(3000)
pub fn context(
  dream_instance: dream.Dream(
    mist.Builder(mist.Connection, mist.ResponseData),
    a,
    old_services,
  ),
  new_context: context,
) -> dream.Dream(
  mist.Builder(mist.Connection, mist.ResponseData),
  context,
  old_services,
)

Set a custom context type for your application

Use this to replace AppContext with your own context type that holds user authentication, session data, or any other per-request information. The type system tracks your context through middleware and controllers.

Example

import dream/servers/mist/server
import dream/servers/mist/server.{context, listen, router, services}

pub type MyContext {
  MyContext(request_id: String, user: Option(User))
}

server.new()
|> context(MyContext(request_id: "", user: None))
|> services(my_services)
|> router(my_router)
|> listen(3000)
pub fn listen(
  dream_instance: dream.Dream(
    mist.Builder(mist.Connection, mist.ResponseData),
    context,
    services,
  ),
  port: Int,
) -> Nil

Start the server and listen for requests

Starts the server on the specified port and blocks forever. This is what you call in your main() function. If the server fails to start, it returns Nil immediately.

This function will panic if you haven’t called router() and services() first— you can’t run a web server without defining what it does.

Example

import dream/servers/mist/server
import dream/servers/mist/server.{listen, router, services}

pub fn main() {
  server.new()
  |> services(initialize_services())
  |> router(create_router())
  |> listen(3000)
}
pub fn listen_with_handle(
  dream_instance: dream.Dream(
    mist.Builder(mist.Connection, mist.ResponseData),
    context,
    services,
  ),
  port: Int,
) -> Result(ServerHandle, actor.StartError)

Start the server and return a handle for stopping it

Like listen(), but returns immediately with a ServerHandle that can be used to stop the server programmatically. Useful for tests and programmatic server control.

Example

import dream/servers/mist/server
import dream/servers/mist/server.{listen_with_handle, router, stop}

pub fn test_server() {
  // Start server and get handle
  let assert Ok(handle) =
    server.new()
    |> router(test_router())
    |> listen_with_handle(8080)
  
  // Make test requests
  let response = http_client.get("http://localhost:8080/test")
  // ... assertions ...
  
  // Stop the server
  stop(handle)
}
pub fn max_body_size(
  dream_instance: dream.Dream(
    mist.Builder(mist.Connection, mist.ResponseData),
    context,
    services,
  ),
  size: Int,
) -> dream.Dream(
  mist.Builder(mist.Connection, mist.ResponseData),
  context,
  services,
)

Set maximum request body size in bytes

Requests with bodies larger than this will be rejected. The default is 10_000_000 bytes (10MB), which is a safe limit for typical JSON and form payloads. Streaming routes are not affected by this limit.

Example

import dream/servers/mist/server
import dream/servers/mist/server.{listen, max_body_size, router, services}

// Limit request bodies to 10MB
server.new()
|> services(my_services)
|> router(my_router)
|> max_body_size(10_000_000)
|> listen(3000)
pub fn new() -> dream.Dream(
  mist.Builder(mist.Connection, mist.ResponseData),
  context.EmptyContext,
  router.EmptyServices,
)

Create a new Dream server with defaults

Returns a server configured with EmptyContext (no per-request data) and EmptyServices (no dependencies). For simple applications, you only need to add a router. For more complex apps, use context() and services() to provide your own types before calling listen().

Simple Example (no context or services)

import dream/servers/mist/server
import dream/servers/mist/server.{listen, router}

server.new()
|> router(my_router)
|> listen(3000)

With Custom Context and Services

import dream/servers/mist/server
import dream/servers/mist/server.{context, listen, router, services}
import gleam/option.{None}

server.new()
|> context(MyContext(request_id: "", user: None))
|> services(my_services)
|> router(my_router)
|> listen(3000)
pub fn router(
  dream_instance: dream.Dream(
    mist.Builder(mist.Connection, mist.ResponseData),
    context,
    services,
  ),
  router_instance: router.Router(context, services),
) -> dream.Dream(
  mist.Builder(mist.Connection, mist.ResponseData),
  context,
  services,
)

Provide your application’s router

The router defines which controllers handle which requests. It must be configured with the same context and services types you’ve set up, which the type system enforces.

Example

import dream/servers/mist/server
import dream/servers/mist/server.{listen, router, services}

pub fn create_router() -> Router(MyContext, Services) {
  router()
  |> route(method: Get, path: "/", controller: controllers.index, middleware: [])
  |> route(method: Get, path: "/users/:id", controller: controllers.show_user, middleware: [])
}

server.new()
|> services(initialize_services())
|> router(create_router())
|> listen(3000)
pub fn services(
  dream_instance: dream.Dream(
    mist.Builder(mist.Connection, mist.ResponseData),
    old_context,
    router.EmptyServices,
  ),
  services_instance: services,
) -> dream.Dream(
  mist.Builder(mist.Connection, mist.ResponseData),
  old_context,
  services,
)

Provide your application’s services

Services are shared dependencies available to all requests—database connections, HTTP clients, caches, etc. Define a type that holds all your services and pass it here.

Example

import dream/servers/mist/server
import dream/servers/mist/server.{listen, router, services}

pub type Services {
  Services(db: Connection, cache: Cache)
}

pub fn initialize_services() -> Services {
  let db = connect_to_database()
  let cache = create_cache()
  Services(db: db, cache: cache)
}

server.new()
|> services(initialize_services())
|> router(my_router)
|> listen(3000)
pub fn stop(handle: ServerHandle) -> Nil

Stop a server that was started with listen_with_handle()

Stops the server process. This sends a shutdown signal to the supervisor. Note: In tests, you typically don’t need to call this - the server will be cleaned up automatically when the test process exits.

Example

import dream/servers/mist/server
import dream/servers/mist/server.{listen_with_handle, router, stop}

pub fn test_server() {
  let assert Ok(handle) =
    server.new()
    |> router(test_router())
    |> listen_with_handle(8080)
  
  // ... use server ...
  
  // Optional - server will be cleaned up automatically when test exits
  stop(handle)
}
Search Document