overview
Fintrospect is a Scala web-framework with an intelligent HTTP routing layer, based on the Finagle RPC framework from Twitter. Via a shared contract, it provides a simple way to implement fast webservice endpoints and HTTP clients which are:
Type-safe
: auto-marshalls all request parameters/bodies into the correct types (including primitives + JSON/XML etc...)Auto-validating
: the presence of required and optional request parameters and bodies are checked before entering service-layer codeAuto-documenting
: runtime generation of endpoint documentation such as Swagger JSON or web sitemap XML. Generates JSON Schema for example object formats to be included in these API docs.Uniform
: reuse the same contract to define both incoming or outgoing Finagle HTTP services. This also allows extremely low effort fake servers to be created
Additionally, Fintrospect provides a number of mechanisms to leverage these routes:
- Easily build type-safe HTTP responses with a set of custom builders for a wide variety of message formats:
- JSON: Argo, Argonaut,
Circe, GSON,
Jackson, Json4S, Play JSON,
Spray JSON
- Auto-marshaling of case classes instances to/from JSON (for
Argonaut
/Circe
/Json4S
/Play
). - Implement simple
PATCH
/PUT
endpoints of case class instances (Circe
only).
- Auto-marshaling of case classes instances to/from JSON (for
- Native implementations of XML, Plain Text, HTML, XHTML
- MsgPack binary format
- JSON: Argo, Argonaut,
Circe, GSON,
Jackson, Json4S, Play JSON,
Spray JSON
- Serve static content from the classpath or a directory
- Template
View
support (with Hot-Reloading) for building responses with Mustache or Handlebars - Anonymising headers for dynamic-path based endpoints, removing all dynamic path elements. This allows, for example, calls to particular endpoints to be grouped for metric purposes. e.g.
/search/author/rowling
becomes/search/author/{name}
- Interacts seamlessly with other Finagle based libraries, such as Finagle OAuth2
- Utilities to help you unit-test endpoint services and write HTTP contract tests for remote dependencies
broad concepts
The main concepts in play:
RouteSpec
: defines the self-describing contract of an HTTP endpointServerRoute
: the binding of aRouteSpec
to a FinagleService
implementing some business-logic, to create an inbound HTTP endpointRouteClient
: the binding of aRouteSpec
to a FinagleService
representing an HTTP client, to create a simple function for making outbound HTTP callsParameterSpec
: defines the acceptable format for a request parameter (Path/Query/Header/Form-field). Provides the auto-marshalling mechanic for serializing and deserializing objects to and from HTTP messagesBodySpec
: similar toParameterSpec
, but applied to the body of an HTTP messageRouteModule
: defines a set ofServerRoute
instances which are grouped under a particular request path. These modules can be combined and then converted to a FinagleService
and attached to a Finagle HTTP server. Each module provides an endpoint under which it's own runtime-generated documentation can be served (eg. in Swagger format)ResponseSpec
: defines the characteristics of a possible response generated by aServerRoute
regarding finagle
Since Fintrospect is build on top of Finagle, it's worth acquainting yourself with it's concepts, which can be found here.
&tldr; finagle primer
- Finagle provides protocol-agnostic RPC and is based on Netty
- It is mainly asynchronous and makes heavy usage of Twitter's version of Scala Futures
- It defines uniform
Service
andFilter
interfaces for both client and server APIs that are effectively a single method...Service: def apply(request : Request) : Future[Response] Filter: def apply(request : RequestIn, service : Service[RequestOut, ResponseIn]) : Future[ResponseOut]
Filters
can be chained together and then applied to aService
, which results in anotherService
. This is useful to apply layers of functionality such as caching headers, retry behaviour, and timeouts.
a note on style
- The code in this guide has omitted imports that would have made the it read more concisely. The sacrifices we make in the name of learning... :)