Skip to content

Instantly share code, notes, and snippets.

@dbousamra
Created November 29, 2016 23:05
Show Gist options
  • Select an option

  • Save dbousamra/f58354b0b3f273649dbf782ddd17b32c to your computer and use it in GitHub Desktop.

Select an option

Save dbousamra/f58354b0b3f273649dbf782ddd17b32c to your computer and use it in GitHub Desktop.

Http4s Basics

--

Overview

When learning http4s, there are 4 main concepts you want to know about:

  • Request
  • Response
  • HttpService
  • Server

Request

A Request encapsulates the concept of an HTTP request. It contains things like the URI/Path of the request, HTTP method used, any headers sent, and the body of the request if there is one.

Response

Like a Request, a Response encapsulates the concept of an HTTP response. it contains things like the HTTP status code, a response body, and any headers.

HttpService

An HttpService is a simple alias for Kleisli[Task, Request, Response]. If that's meaningful to you, great. If not, don't panic: Kleisli is just a convenient wrapper around a Request => Task[Response], and Task is an asynchronous operation. We'll teach you what you need to know as we go, or you can, uh, fork a task to read these introductions first:

  • [Scalaz Task: The Missing Documentation]
  • [Kleisli: Composing monadic functions]

Breaking down that type signature (Request => Task[Response]), an HttpService represents an HTTP endpoint that can take in an HTTP request, and will return some Response, asynchronously (the Task component of the signature.).

That's really it - an HttpService is a function from Request => Response in the Task effect. Because they are in essence, just functions, it means they can be composed, merged and transformed, just like any other function.

Server

And HttpService is great and all, but we need some machinery to actually route incoming connections to an HttpService. A Server is just something that accepts an HttpService (or many), and binds them to connections. http4s supports multiple server backends.

A quick example

... A quick example here to whet peoples appetites ...

Imports

... Talk about imports here ...

Understanding HttpServices

... Talk more in depth about kleisli etc here ...

Working with HttpServices

Constructing HttpServices

There are several different ways of creating an HttpService.

To create an empty HttpService that always returns a 404 Not Found response, you can use the factory method empty:

val emptyService: HttpService = HttpService.empty

Not overly useful. Suppose we have a constant value of type Task[Response], we can lift that into a function that always returns that response using const:

val response: Task[Response] = Ok("Always returns 200")
val constantlyOkService: HttpService = Service.const(response)

If we have a function returning Task[Response], we can lift that into an HttpService using lift:

val liftedService: HttpService = HttpService.lift { req =>
  if (req.method == Method.GET) {
    Ok("You sent a GET request!")
  } else {
    Ok("You sent something other than GET!")
  }
}

These are fairly low level ways to construct HttpService's, but they do illustrate that it's nothing more than a function from A => B. https has a nicer way to construct them using the DSL:

import org.http4s.dsl._

val dslService: HttpService = HttpService {
  case req @ GET -> Root => {
    Ok("Using the DSL")
  }
}

The org.http4s.dsl._ brings in a bunch of new functionality like path matching, etc etc ... fill this bit in ...

The HttpService { } apply function has the signature: def apply(pf: PartialFunction[Request, Task[Response]], default: HttpService = empty): HttpService. It takes in a PartialFunction from Request to Task[Response], and a default service if nothing matches (which defaults to empty - 404 Not Found). It proceeds to match top to bottom.

The http4s DSL

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment