Model
Loading

Model

The akka HTTP model contains a mostly immutable, case-class based model of the major HTTP data structures, like HTTP requests, responses and common headers. It also includes a parser for the latter, which is able to construct the more structured header models from raw unstructured header name/value pairs.

Overview

Since akka-http-core provides the central HTTP data structures you will find the following import in quite a few places around the code base (and probably your own code as well):

import akka.http.model._

This brings in scope all of the relevant things that are defined here and that you’ll want to work with, mainly:

  • HttpRequest and HttpResponse, the central message model
  • headers, the package containing all the predefined HTTP header models and supporting types
  • Supporting types like Uri, HttpMethods, MediaTypes, StatusCodes, etc.

A common pattern is that the model of a certain entity is represented by an immutable type (class or trait), while the actual instances of the entity defined by the HTTP spec live in an accompanying object carrying the name of the type plus a trailing plural 's'.

For example:

  • Defined HttpMethod instances live in the HttpMethods object.
  • Defined HttpCharset instances live in the HttpCharsets object.
  • Defined HttpEncoding instances live in the HttpEncodings object.
  • Defined HttpProtocol instances live in the HttpProtocols object.
  • Defined MediaType instances live in the MediaTypes object.
  • Defined StatusCode instances live in the StatusCodes object.

HttpRequest / HttpResponse

HttpRequest and HttpResponse are the basic case classes representing HTTP messages.

An HttpRequest consists of

  • method (GET, POST, etc.)
  • URI
  • protocol
  • headers
  • entity (body data)

Here are some examples how to construct an HttpRequest:

import HttpMethods._

// construct simple GET request to `homeUri`
val homeUri = Uri("/abc")
HttpRequest(GET, uri = homeUri)

// construct simple GET request to "/index" which is converted to Uri automatically
HttpRequest(GET, uri = "/index")

// construct simple POST request containing entity
val data = ByteString("abc")
HttpRequest(POST, uri = "/receive", entity = data)

// customize every detail of HTTP request
import HttpProtocols._
import MediaTypes._
val userData = ByteString("abc")
val authorization = headers.Authorization(BasicHttpCredentials("user", "pass"))
HttpRequest(
  PUT,
  uri = "/user",
  entity = HttpEntity(`text/plain`, userData),
  headers = List(authorization),
  protocol = `HTTP/1.0`)

All parameters of HttpRequest have default values set, so e.g. headers don't need to be specified if there are none. Many of the parameters types (like HttpEntity and Uri) define implicit conversions for common use cases to simplify the creation of request and response instances.

An HttpResponse consists of

  • status code
  • protocol
  • headers
  • entity

Here are some examples how to construct an HttpResponse:

import StatusCodes._

// simple OK response without data created using the integer status code
HttpResponse(200)

// 404 response created using the named StatusCode constant
HttpResponse(NotFound)

// 404 response with a body explaining the error
HttpResponse(404, entity = "Unfortunately, the resource couldn't be found.")

// A redirecting response containing an extra header
val locationHeader = headers.Location("http://example.com/other")
HttpResponse(Found, headers = List(locationHeader))

Aside from the simple HttpEntity constructors to create an entity from a fixed ByteString shown here, subclasses of HttpEntity allow data to be specified as a stream of data which is explained in the next section.

HttpEntity

An HttpEntity carries the content of a request together with its content-type which is needed to interpret the raw byte data.

Akka HTTP provides several kinds of entities to support static and streaming data for the different kinds of ways to transport streaming data with HTTP. There are four subtypes of HttpEntity:

HttpEntity.Strict
An entity which wraps a static ByteString. It represents a standard, non-chunked HTTP message with Content-Length set.
HttpEntity.Default
A streaming entity which needs a predefined length and a Producer[ByteString] to produce the body data of the message. It represents a standard, non-chunked HTTP message with Content-Length set. It is an error if the provided Producer[ByteString] doesn't produce exactly as many bytes as specified. On the wire, a Strict entity and a Default entity cannot be distinguished. However, they offer a valuable alternative in the API to distinguish between strict and streamed data.
HttpEntity.Chunked
A streaming entity of unspecified length that uses Chunked Transfer Coding for transmitting data. Data is represented by a Producer[ChunkStreamPart]. A ChunkStreamPart is either a non-empty Chunk or a LastChunk containing optional trailer headers. The stream must consist of 0..n Chunked parts and can be terminated by an optional LastChunk part (which carries optional trailer headers).
HttpEntity.CloseDelimited
A streaming entity of unspecified length that is delimited by closing the connection ("Connection: close"). Note, that this entity type can only be used in an HttpResponse.
HttpEntity.IndefiniteLength
A streaming entity of unspecified length that can be used as a BodyPart entity.

Entity types Strict, Default, and Chunked are a subtype of HttpEntity.Regular which allows to use them for requests and responses. In contrast, HttpEntity.CloseDelimited can only be used for responses.

Streaming entity types (i.e. all but Strict) cannot be shared or serialized. To create a strict, sharable copy of an entity or message use HttpEntity.toStrict or HttpMessage.toStrict which returns a Future of the object with the body data collected into a ByteString.

The HttpEntity companion object contains several helper constructors to create entities from common types easily.

You can pattern match over the subtypes of HttpEntity if you want to provide special handling for each of the subtypes. However, in many cases a recipient of an HttpEntity doesn't care about of which subtype an entity is (and how data is transported exactly on the HTTP layer). Therefore, a general HttpEntity.dataBytes is provided which allows access to the data of an entity regardless of its concrete subtype.

Note

When to use which subtype?
  • Use Strict if the amount of data is small and it is already in the heap (or even available as a ByteString)
  • Use Default if the data is generated by a streaming data source and the size of the data is fixed
  • Use Chunked to support a data stream of unknown length
  • Use CloseDelimited for a response as an alternative to Chunked e.g. if chunked transfer encoding isn't supported by a client.
  • Use IndefiniteLength instead of CloseDelimited in a BodyPart.

Header model

Akka HTTP contains a rich model of the common HTTP headers. Parsing and rendering is done automatically so that applications don't need to care for the actual syntax of headers. Headers not modelled explicitly are represented as a RawHeader.

See these examples of how to deal with headers:

import akka.http.model.headers._

// create a ``Location`` header
val loc = Location("http://example.com/other")

// create an ``Authorization`` header with HTTP Basic authentication data
val auth = Authorization(BasicHttpCredentials("joe", "josepp"))

// a method that extracts basic HTTP credentials from a request
case class User(name: String, pass: String)
def credentialsOfRequest(req: HttpRequest): Option[User] =
  for {
    Authorization(BasicHttpCredentials(user, pass)) <- req.header[headers.Authorization]
  } yield User(user, pass)

Parsing / Rendering

Parsing and rendering of HTTP data structures is heavily optimized and for most types there's currently no public API provided to parse (or render to) Strings or byte arrays.

Contents