Skip to content

Instantly share code, notes, and snippets.

@vkostyukov
Last active July 19, 2018 16:39
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save vkostyukov/65ba8c381ae5c6039dba to your computer and use it in GitHub Desktop.
Save vkostyukov/65ba8c381ae5c6039dba to your computer and use it in GitHub Desktop.
Finch 1.0

The Future Finch writeup defines a vector in which Finch 1.0 should be developed. The goal for 1.0 is to build very clean, simple, well-tested and composable core based on purely functional constructs and immutable data. The core will provide a solid ground for the micro-frameworks, which should land in Finch 2.0.

This document consists of two parts. The first part presents a high-level picture of Finch 1.0. The second part describes required steps we, Finch contributors and maintainers, have to make in order to bring the library to its first stable version.

One Abstraction to Rule Them All

Looking at the current API, one can find a slight correlation between Routers and RequestReaders. They both take a request and produces a value of type A from it. They both functions: HttpRequest => A. Keeping that in mind, the idea of composing them into a single thing (perhaps Router) has found its supporters. The next reasonable step would be to completely merge those abstractions into a single one (perhaps Endpoint). This would simplify the API surface while fitting pretty nicely into the concept of "Your REST API as a Monad". Although, the main goal here is to unify similar concept.

While the union of RequestReader and Router looks pretty solid it still might be extended to carry in ResponseBuilders. Our previous experiments with the micro package have shown that the top-level monad Micro lacks the information about response encoding (what content type to use, what headers to send, etc). Perhaps, this information should be available per endpoint (or Endpoint <- see what I did here?). Thus, the ultimate goal is one abstraction Endpoint[A] that knows 1) how to route the HttpRequest, 2) how to fetch some value of type A from it and 2) how to encode this value into an HttpResponse.

This approach will also help us to solve the issue we've found earlier when the content-type should be explicitly defined for each endpoint. Finally, this approach partially answers the question from Future Finch. Q: "How to organize my codebase?". A: "Define independent endpoints you want to serve". Thus, an idiomatic Finch code (as per 1.0) looks like a bunch of Endpoints (values) organized in any reasonable way.

The user-facing API might look like (this is just a sketch):

val postTicket: Endpoint[Ticket] = 
  post("users" :: path.as[Int] :: "tickets") { userId =>
    Ticket(userId, "SFO -> OVB").toFuture
  } withHeader(t => "X-Created" -> t.id)

Httpx.serve(":8081", postTicket.withContentType("application/json").toService)

Note that this unification implies one pretty serious restriction: fixed request type. We've already discussed that this pattern doesn't fit well into the Finch concepts and might be easily replaced with RequestReader (or Endpoint in our case).

Roadmap to 1.0

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