Akka, Concurrency, etc.

Akka HTTP Request and Response models

August 11, 2018

In this article, I am going to review the HTTP model in Akka HTTP, which is described here in the official document and defined as follows:

case-class based model of all the major HTTP data structures, like HTTP requests, responses and common headers.

This will be the base for understanding Marshalling/Unmarshalling infrastructure in Akka HTTP, which I will discuss in upcoming articles.

HttpRequest

The case class HttpRequest represents, as the name indicates, an HTTP request. When you send an HTTP request, it looks like this:

POST             https://example.com HTTP/1.1
Host:            example.com
Connection:      keep-alive
Accept:          application/json
User-Agent:      Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,ja;q=0.8

{"field1": "some value", "field2": 100}

The above example can be decomposed into different parts as follows:

The format of HTTP requests is clearly described in the following paragraph in RFC7230. It’s worth reading:

A client sends an HTTP request to a server in the form of a request message, beginning with a request-line that includes a method, URI, and protocol version (Section 3.1.1), followed by header fields containing request modifiers, client information, and representation metadata (Section 3.2), an empty line to indicate the end of the header section, and finally a message body containing the payload body (if any, Section 3.3).

In the Akka HTTP source code, the HttpRequest case class consists of

final class HttpRequest(
  val method:   HttpMethod,                //(GET, POST, etc.)
  val uri:      Uri,                       //URI
  val headers:  immutable.Seq[HttpHeader], //HTTP headers
  val entity:   RequestEntity,             //entity (i.e.) body
  val protocol: HttpProtocol)              //HTTP 1.1, 1.0, etc
  extends ... HttpMessage { ... }

where you can find:

  • Available HTTP methods (HttpMethod) here
  • Available headers (HttpHeader) here
  • Available protocols (HttpProtocol) here

Also you see that HttpRequest extends the HttpMessage trait,

sealed trait HttpMessage { ..}

which is the base trait for both HttpRequest, and HttpResponse which we will see in the next section.

HttpResponse

Similar to HTTP requests, an HTTP response example looks like below:

HTTP/1.1 200 OK
Server: akka-http/10.1.3
Date: Sat, 11 Aug 2018 16:17:11 GMT
Content-Type: application/json
Content-Length: 28

{"name":"Joh Don","age":150}

There is slight difference from the request as in RFC7230. The main difference is that an HTTP response has a status line, while an HTTP request had a request line.

A server responds to a client’s request by sending one or more HTTP response messages, each beginning with a status line that includes the protocol version, a success or error code, and textual reason phrase (Section 3.1.2), possibly followed by header fields containing server information, resource metadata, and representation metadata (Section 3.2), an empty line to indicate the end of the header section, and finally a message body containing the payload body (if any, Section 3.3).

If there is a body in the HTTP request, the headers and the body are separated by a blank line, like below.

In Akka HTTP, the HttpResponse case class consists of

final class HttpResponse(
  val status:   StatusCode,                // HTTP Status Code
  val headers:  immutable.Seq[HttpHeader], // HTTP headers
  val entity:   ResponseEntity,            // entity (i.e.) body
  val protocol: HttpProtocol               // HTTP 1.1, 1.0, etc
) extends ... with HttpMessage {...}

where you can find:

  • Available HTTP methods (HttpMethod) here
  • Available headers (HttpHeader) here
  • Available protocols (HttpProtocol) here

Again, like HttpRequest, HttpResponse extents the HttpMessage trait.

HttpEntity

For those who are used to other HTTP frameworks or libraries, the word ”entity” might sound unfamiliar, because we cannot find the word in the following family of “Hypertext Transfer Protocol (HTTP/1.1)” RFCs:

(We see entity-tag but that’s different from entities in Akka HTTP.)

So what is an ”entity” in Akka HTTP? As briefly touched in the official documentation, an entity is the body of an HTTP request or response.

an entity (body data)

That’s just it. An entity is a body, and HttpEntity models the entity.

To be honest, I am not sure why it was named as HttpEntity but not HttpBody (in Akka HTTP, there is no such class or trait named HttpBody). I guess there is a valid reason for this. Anyway, when you see the word ”entity”, you can assume that is the body of a request or a response.

In Akka HTTP, RequestEntity and ResponseEntity, which represent the HTTP request body and the response body, extend HttpEntity.

sealed trait RequestEntity extends HttpEntity ... {...}
sealed trait ResponseEntity extends HttpEntity ... {...}

As they are traits, there are concrete classes extending from them. They are described in the HttpEntity section of the official doc, which are:

  • HttpEntity.Strict
  • HttpEntity.Defuault
  • HttpEntity.Chunked
  • HttpEntity.CloseDelimited
  • HttpEntity.IndefiniteLength

and they are defined like below. The below case class definition is not very accurate, but simplified for the sake of easy understanding, still holding the essence of the actual definition.

final case class Strict(
  contentType: ContentType,
  data: ByteString
) extends ... HttpEntity
// simplified, it doesn't directly extend HttpEntity
final case class Default(
  contentType:   ContentType,
  contentLength: Long,
  data:          Source[ByteString, Any]
) extends ... HttpEntity
// simplified, it doesn't directly extend HttpEntity
final case class Chunked(
  contentType: ContentType,
  chunks: Source[ChunkStreamPart, Any]
) extends ... HttpEntity
// simplified, it doesn't directly extend HttpEntity

The last two, CloseDelimited and IndefiniteLength are bit more complicated, and less frequently used in practice, so we are not going to cover them here.

The meaning and behavior of these concrete classes will become clearer when you have better understanding about Marshalling and Unmarshalling, as well as Streaming Support in Akka HTTP which I also explained in a past article.

Summary

Up to this point, we have covered how an HTTP request and response can be decomposed into smaller components, and what HTTP ”entity” means - it is just the HTTP body of a request or a response, and HttpEntity has more specialized types like Strict, Default and Chuked.

As said at the beginning, to understand Marshalling and Unmarshalling, which is difficult when you look into the internals, it is crucial to have an idea about how HttpRequest, HttpResponse and HttpEntity are related to each other.

From the next article, I’ll start talking about Marshalling and Unmarshalling, which hopefully clarifies points not touched in the official doc.


Richard Imaoka

Written by Richard Imaoka, a Scala developer . You can find me on twitter, and github.