changelog & migration guide

Roadmap/Release Notes/Migration Guide

The main API is stable, but expect some amount of breaking changes around major releases as new features are added. All breaking changes are documented with a migration step where possible.


  • Add strict Content-Type header checking for RouteSpecs based on consuming() and withBody() settings. Option for non-strictness.
  • Add strict Accept header checking for RouteSpecs based on producing() settings. Option for non-strictness.
  • Add integrated self-hosted Swagger UI/ReDoc UI module


  • use Java 11 to build
  • upgrade some dependencies (including Argo)


  • Upgrade to various dependencies, including Finagle to version 19.5.0. This has resulted in various API changes due to Finagle dropping the dependency on Netty v3 (now v4).


  • Upgrade Finagle to version 18.8.0. H/T @fuCtor


  • Fix #46 - ETags should be wrapped in quotes.


  • Upgrade Finagle to new version


  • Upgrade Finagle to new version (with new versioning scheme)


  • Replace combine method with andThen for clarity and consistency with the Filter API


  • Upgrade to various libraries, including Finagle 7.0.0 \o/


  • Upgrade to Finagle 6.45.0


  • Fix for #39. Routes can no longer contain duplicate response codes.
  • Fix for #39. Swagger renderer was producing duplicate model definitions when same object was returned in multiple responses.


  • Fix tag duplication for routes in Swagger renderer.


  • Fix tag ordering for routes in Swagger renderer.


  • Implemented #42 - Support for custom tags in Swagger documentation rendering. Thanks to @ncreep for the PR.
  • Bumped Circe and Json4s versions


  • Upgrade Finagle to v6.44.0


  • Ability to override the status of a View
  • Upgrade Finagle to v6.43.0


  • Adding details of traceId and request to DebuggingFilters.PrintResponse


  • Performance tweak - only decode bodies once when using the Auto filters.
  • Improved error messages in case of broken contract scenarios.
  • API Improvement: hidden ParameterSpec.apply(). Should be using ParameterSpec.<type>() methods and then using map() instead. This hides the ParamType from the API user.
  • API Deprecations: moving to Path.of() and Body.of() instead of Path() and Body() in the case of custom path/body types. This aids API discoverability


  • Bugfix: #38 - Adding missing type signature on Path to remove reflective calls flag warning.


  • Bugfix: Auto filters fail if no body is specified in the route contract.


  • Performance: the RouteSpec validation mechanism now caches the parsed parameters, so further attempts to obtain parameters will use the pre-parsed version.


  • General tidy of Parameter hierarchy. No visible API change
  • Rename of Request/ResponseFilter helpers to be "verby". The names are very similar, just more verby! :)


  • BugFix #34 Upgrade to finagle-http 6.42.0.
  • Readded Scala 2.12.X support, as #34 is fixed.
  • Reimplemented Extractors, so successful extractions are now NOT wrapped in an Option. Optional extractions are now denoted via the type Extraction[Option[T]] rather than just Extraction[T].


  • Added Composite, to add support for objects that are made up of several query or header params.


  • Add support for Value[T] types that can be automatically marshalled to/from the request. ParameterSpec.string().as[MyStringType]
  • (Small) Breaking. Removed usages and implementation of ParameterSpecSupplier. Use the Value[T] trait instead.
  • Change RouteClient to be generified on the response type. This means that we can tidy up code for extraction of response bodies. \o/


  • Added custom extraction logic to Body.<--? so that if the response code is 404, then extraction is NOT attempted, and a Extracted(None) is returned


  • (Small) Breaking: Reworking of custom ParameterSpec and BodySpec. The "name" and "description" fields have been moved out of the spec and onto the Body/Query/Header/FormField instance. This means that you can reuse the same custom type for multiple parameters using the same instance of the Spec (ie. you don't have to parameterize the creation of the spec). Example fix: Query.required(ParameterSpec.string("name", "description")) --> Query.required(ParameterSpec.string(), "name", "description")
  • Upgrade to various dependency versions, including circe-0.7.0.


  • Release for Scala 2.12.0 and 2.11.0 (don't ask - bintray/maven problems


  • Release for Scala 2.12.0


  • Behaviour: Changed default string ParameterSpec and Body validation so that empty strings are NOT valid. This should only affect untyped string fields in forms or queries, as custom deserialising logic would otherwise catch. This should be the default behaviour, as forms always send empty text values anyway, and it doesn't make sense to marshall empty values into another type. Behaviour is overridable on a case-by-case basis by passing StringValidations.EmptyIsValid when defining the Parameter/Body/Field.


  • Added RenderView.Redirect to allow redirection of responses from a route that would otherwise generate a View


  • Added missing number() method for Double on JSON format objects
  • Bugfix #32 - Circe displaying ints as decimal when using JsonFormat.number()
  • (Small) breaking: Replaced function with Service[T: Boolean] in ApiKey
  • (Small) breaking: Body, BodySpec, ParameterSpec, ApiInfo API tidying - description fields now a default nullable String instead of a pointless nullable Option[String]. Although nulls are bad m'kay, this is better since the following args are also defaultable, thus making the required Some(x) wrapping pointless. To fix, unwrap the option :)


  • Upgrade to various dependency versions, including finagle-http 6.41.0.
  • Breaking: remodel/repackage of ResponseBuilder instantiation for custom formats. This only affects API users if using implicit conversion of Status objects to ResponseBuilder. This conversion has been replaced with explicit methods on ResponseBuilder objects for each status code, along with a ResponseBuilderMagnet to convert the various input content types (such as String, JSON, Buf, etc) - see below: Simple to fix, but different enough to warrant a new version number:
    1. Replace Status.Ok("content").withHeader(etc) type calls with ResponseBuilder.Ok("content").withHeader(etc)
    2. Replace <format>.ResponseBuilder.implicits._ import with <format>.ResponseBuilder._. This import also brings in the various conversions for the ResponseBuilderMagnet.
  • (Small) Breaking: rework of Auto conversion for format objects. <format>.Filters.AutoXXX has become <format>.Auto.XXX.


  • (Small) Breaking: Tidying up of Body API for clarity. Bodies should only be instantiated using a method from Body, be it Body.<format>() or Body(<format>.bodySpec()) for custom types.
  • (Small) Breaking: Moved methods from JsonFormat objects onto main format object - e.g. Circe.JsonFormat.bodySpec -> Circe.bodySpec


  • Added module fintrospect-jackson to support Jackson JSON library. See Jackson to get the Format util and ResponseBuilder for this format.
  • Performance tweaks so we cache the extracted request parameters. This means that we can drop the RouteValidation options as they were introduced specifically to give the user an option as to when to extract.


  • AKA: The slight API-tidy release!
  • Deprecation: Renamed ModuleSpec to be RouteModule. Readded ModuleSpec constructors with identical (but deprecated) methods, so no break will occur. Please update your apps.
  • (Small) Breaking: Simplified signature of Module.combine() to return a new Module instead of a ServiceBinding. This means that combined lib user can just call toService() on the combined module instead of calling Module.toService(serviceBinding), so combined Modules are just Modules themselves.


  • Remodelled all parameters so they are modelled as a Seq instead of a Set. Fixes that you can't send multiple parameters with the same value.
  • Bugfix Issue #27. Empty multipart file fields not being detected as missing during extraction.


  • Added Body.binary, for transmission of binary HTTP messages
  • Added support for MultiPart forms (both strict and with error-reporting).
  • Tweaked Mustache implementation and removed a dependency.


  • Upgrade to various dependency versions, including finagle-http 6.40.0.


  • Performance tweaks to path moving.
  • Upgrade to various dependency versions, including GSON and circe.


  • All response Builders can now take a AsyncStream[T], so you can stream responses in a typesafe way. See streaming example.
  • Upgrade to various dependency versions, including circe, Json4s & scala-xml.


  • Replaced Circe.JsonFormat.patchBodySpec() with patchBody() to ease use of Patch endpoint creations.


  • Upgrade to various dependency versions, including Circe 0.5.4.
  • Circe.JsonFormat: Added explicit patcher() method to allow patch updates for case class instances (via auto-marshalling JSON modules).
  • Added support to StrictContentTypeNegotiation for routes serving multiple content types. See StrictMultiContentTypeRoute example.


  • Bugfix: Issue #24. Remove transitive dependency on sl4j-simple in fintrospect-handlebars to avoid SL4J warnings.


  • Breaking: Repackage of JSON message format libraries. io.fintrospect.formats.json.<LibraryName> are now just io.fintrospect.formats instead. To fix, simply find/replace the package names in your source.
  • Breaking: Split Json4s.Native and Json4s.Jackson into their own top-level message objects. The mapping is Json4s.Native -> Json4s/Json4sDoubleMode and Json4s.Jackson -> Json4sJackson/Json4sJacksonDoubleMode, so simply find/replace references in your source.
  • Upgrade to various dependency versions, including Finagle 6.38.0 and Circe 0.5.2.


  • Bugfix: Issue #23. On invalid request, AutoFilters blow up instead of producing BadRequest response


  • Added MsgPack library support. Import new module fintrospect-msgpack to activate this support.


  • Upgrade to various dependency versions, including Finagle 6.37.0 and Circe 0.5.1.


  • (Possible) Breaking: Refactored StaticModule to allow serving of directory-based assets. Introduced Classpath and Directory ResourceLoaders to allow for this change.


  • Addition of Contract and ContractProxyModule. This (optional) formalisation of client contracts allows simple exposing of a client API contract via Swagger. See ContractProxyExample.
  • (Unlikely) Break: Renamed of IncompletePath to UnboundRoute for clarity. This should be transparent to end users.
  • Refactor of Parameter types and traits. This should be transparent to end users.
  • Removal of Generics in RequestFilters. Should make code using these filters easier - by just removing Generics.


  • Please ignore this release and roll back to 13.4.0.


  • Upgrade to Finagle 6.36.0
  • Fixed site API docs
  • Added Body.webform(), which allows errors to be collected for feedback to the user. See formvalidation example
  • Breaking: Removed NotProvided extraction option. Extraction now exposes an Option instead
  • Breaking: Renamed InvalidParameter to ExtractionError
  • Breaking: Repackage of some classes from io.fintrospect.parameters to io.fintrospect and io.fintrospect.util


  • Option for empty string validation to be rejected as InvalidParameter in QueryParameters et al.
  • Breaking: removed unused HttpRequestResponseUtil:contentFrom() method. Simply use request.contentString instead
  • ResponseFilter.ReportingRouteLatency() now blocks for reporting latency, as using onSuccess was not accurately reporting.


  • Dynamic reloading of templates. See implementations of Templates (Mustache and Handlebars), or templating example.
  • Breaking; Combined RenderMustacheView and RenderHandlebarsView into RenderView.


  • Upgrade of some library dependency versions (scala-xml and scala-parser-combinators)


  • v13! Unlucky for some (but hopefully not for us!)
  • Dropped cross build to Scala 2.10. This is forced since finagle-http is dropping it.
  • Breaking: Removal of all previously deprecated items in: ResponseBuilder, Filters andFintrospectModule. See below for notes on replacement.
  • Breaking: With this release, we have repackaged Fintrospect into a core module fintrospect-core and a set of add-on modules (fintrospect-circe, fintrospect-mustache etc.). The artifacts also now live in a new Maven group: io.fintrospect. The module dependencies have been internalised, so various modules have explicitly internalised their dependencies. Please read the installation guide for the new mechanism, but as a simple example, if previously your dependencies for fintrospect were:
libraryDependencies ++= Seq(
"com.twitter" %% "finagle-http" % "6.35.0",
"io.github.daviddenton" %% "fintrospect" % "12.21.0"
"io.circe" %% "circe-generic" % "0.4.1")

... then you now rely on the fintrospect-core and fintrospect-circe modules. Your dependencies should now be:

libraryDependencies ++= Seq(
"io.fintrospect" %% "fintrospect-core" % "13.0.0",
"io.fintrospect" %% "fintrospect-circe" % "13.0.0")


  • Bugfix: Issue #21 Form extraction fails on empty fields


  • Added Validator to provide error collection.
  • Ability to map ParameterSpecs. This comes in useful when declaring ParameterSpecs of AnyVal wrapper classes.
  • (Small) Break: repackage of filter classes io.fintrospect.util -> io.fintrospect.filters. Renames are: Filters.Request -> RequestFilters, Filters.Response -> ResponseFilters
  • (Small) Break: Extractable renamed to Extractor


  • Bugfix: Issue #20 Static Module now resolves to index.html for default paths


  • Convenience methods added to Extraction.


  • Tidied up Extractables to finalise (again).


  • Bugfix: Extractables short-circuiting incorrectly when last parameter is optional (issue #19).


  • Bugfix: Extractables must return an Option to not shortcircuit in valid situations (issue #18).


  • Facility to override body and parameter validation in RouteSpec - pass in a different RequestValidation instance
  • Finalised extraction logic, including embedding of Extractables


  • More experimental extraction logic, including rename of Validatable -> Extractable


  • Added utility filters
  • More work on composites and extraction


  • (Small) breaking change: Added reasons to invalid parameter validation. This means that the badRequest() method of ModuleRenderer implementations need to change to also take the Seq(InvalidParameter) instead of just Seq[Parameter]. Easily fix by inserting the first line of val params = into your badRequest() if you want to ignore the reason.
  • Massive tidy-up of Extraction logic + introduction of experimental support for cross-parameter validation via for comprehensions


  • Bugfix: Empty forms can be retrieved from a request, even when they have required fields (issue #15).
  • Bugfix: Cache filters should only apply to successful responses (issue #16).


  • Slight refactor of Auto*** filters to make usage simpler. May involve a rearrangement of implicit parameters (previously included the Status) depending on the use-case, but in majority of cases should not be breaking.
  • Extended auto-marshalling support for XML responses to Elem. See XML.Filters.Auto***.
  • Filter to allow multiple multiple body types to be accepted on a single route.


  • Added auto-marshalling support for JSON libraries which support it (Circe, Argonaut, Json4S, Play. See Circe.Filters.Auto*** filter constructors to wrap your existing domain services, or see Circe example for exact usage.


  • Upgrade Finagle dependency to 6.35.0. Note that this is (apparently) the last Scala 2.10.X supporting Finagle release.


  • Added HeapDump utility service to programatically generate a hprof file.
  • Similar to Query, added support for multiple header parameters with same name. See *() on Header.required|optional.
  • Support for serving strict content-type negotiation and multiple content types to be served from a single route. See example strictcontenttypes.
  • Added a number of useful general-case filters. See Filters.
  • Added a number of useful cache-control filters. See Caching.
  • Upgrade of Circe version to 0.4.1
  • Upgrade of Scala version to 2.11.8


  • Renamed and moved implicit method conversions for response building for clarity from X.toFuture to X.implicits.XXXToFuture. Possible small break if you've imported the implicits exactly instead of with a wildcard.


  • Added convenience methods for creating ResponseSpec object for auto-encoding JSON libraries.


  • Added generification of ModuleSpec in the Request type as well as the Response type. This means that we can plug in other Finagle frameworks which vary in their Request type, such as Finagle-OAuth2. Likelihood of breaks is small, so just a minor version bump. In all cases, just replace ModuleSpec[X] and ServerRoute[X] with ModuleSpec[Request, X] and ServerRoute[Request, X] .
  • Upgrade Finagle dependency to 6.34.0
  • Added examples for templating and OAuth2 integration


  • Bolstered infra utilities to be friendlier for testing applications outside of a container


  • Added UUID parameter type


  • For performance, all JSON responses are now rendered in compact format by default when using a JSON library and the native node type (as opposed to string). This shouldn't really break anything in your code unless you're relying on comparisons with hardcoded JSON strings - :)


  • Added symbol support to JsonFormat object generation - see objSym()
  • Upgrade of Circe to 0.3.0 - note the rename of the circe-parse package dependency to circe-parser


  • Bugfix: Static resources not found when Static module is at the root context (issue #14).
  • Upgrade finagle dependency to 6.33.0


  • Significant performance improvement by route matching on ModuleSpec context first and then on the whole path. This means that ModuleSpec contexts now CANNOT be shared at all, due to the routing matching just the Module context to select the Module and then then the rest of the path within that Module. For static resources, StaticModule instances that share their context with another (e.g. for dynamic web resources at the root context), need to come before any partner ModuleSpec when creating the final service. Also, any overlapping ModuleSpecs will need to be combined into one.


  • New documentation and project site


  • Breaking change: Moved non-JSON ResponseBuilder classes to be consistent with other codecs. E.g. io.fintrospect.formats.xml.XmlResponseBuilder moves to io.fintrospect.formats.Xml.ResponseBuilder.
  • (Unlikely) Breaking change: Rename of ResponseBuilderMethods trait to AbstractResponseBuilder.
  • (Unlikely) Breaking change: Rename of SprayJson to Spray (for consistency).
  • Deprecation of FintrospectModule to be replaced with ModuleSpec and Module for consistency.
  • Added support Circe JSON library out of the box. See Circe to get the Format util and ResponseBuilder for this format.
  • Added templating support for Mustache and Handlebars - similar to the JSON libraries, these require extra dependencies to be added to build.sbt.
  • Added StaticModule for serving static resources from the classpath.
  • Added SiteMapModuleRenderer for XML descriptions of web modules.
  • Added parenthesis for ResponseBuilder build() method for consistency.


  • Upgrade to Finagle 6.31.0.
  • Added ability to bind Scala Option to optional parameter values instead of just concrete values.
  • Added Security to module endpoints, specifically ApiKey which adds a security filter to all requests. Documentation generation is included, but unfortunately the current Swagger UI does not support this properly due to a bug. As a workaround until Swagger UI is fixed (if you need it), simply add the required ApiKey "parameter" to every endpoint, which will allow the best of both worlds (although you will not need to check for the presence of the API-Key in your routes since this will already be handled by Fintrospect.
  • Added support GSON JSON library out of the box. See Gson to get the Format util and ResponseBuilder for this format.
  • New example full and documentation rewrite to show off advanced feature usage of the library.


  • Added convenience methods to remove boilerplate for auto marshall/demarshall JSON when creating body and parameters specs.


  • Added convenience implicit conversions from Status to ResponseBuilder to Response. This tidies up the code nicely since you can use the Status as follows: Status.Ok("content")


  • Bugfix: ArrayIndexOutOfBoundsException when handling an empty form (issue #12).


  • Added using Buf's and ChannelBuffers to create HTTP responses.
  • Removed deprecated methods from ResponseBuilderMethods.


  • Added convenience mechanism to create custom parameters.


  • Bugfix for ordering of the routes when matching a path (issue #11).


  • Upgrade to Finagle 6.30.0, which has resulted in... < drumroll >
  • Breaking change: Musical chairs from the Finagle team with the finagle-httpx package, which is now renamed to finagle-http. Just globally replace httpx with http and all should be good.
  • Removed CorsFilter. You can now use the Cors.HttpFilter supplied by finagle-http instead.


  • Added 6 and 7 arity path lengths.


  • Added support Play JSON library out of the box. See Play to get the Format util and ResponseBuilder for this format.


  • Tiny break: Moved ApiInfo class to io.fintrospect.renderers.swagger2dot0 package as was messing up the place.
  • Inlined JsonResponseBuilder - this shouldn't be breaking anything - identically implement JsonLibrary instead for custom JSON formats.
  • Added support Argonaut JSON library out of the box. See Argonaut to get the Format util and ResponseBuilder for this format.
  • Added XHtml support (based on native XML).


  • Bugfix for Json4S builder method.


  • Upgrade from finagle-http v6.27.0 to finagle-httpx v6.29.0, as the former is EOL. This will result in a significant amount of breaking changes due to Finagle using their own httpx classes instead of Netty equivalents:
    • References to HttpRequest/Response Netty classes are now Request/Response instead
    • References to HttpResponseStatus changed to Status
    • References to HttpMethod.GET/POST/... changd to Method.Get/Post/...
    • References to Http.XXX() will now use Httpx.XXX() instead
  • Other than the above, no actual changes to the Fintrospect API or how it works have been made.
  • Added OK and HttpResponse alias methods to the ResponseBuilder to avoid name clashes with new HttpX methods. Deprecated Ok() and Response() methods for clarity.


  • Changed format of "X-Fintrospect-Route-Name" header to use : instead of . in to describe the route URL - as URLs often have . in (for file extensions).


  • Added support for other Scala JSON libraries - Json4S (Native and Jackson) and SprayJson out of the box. See Json4s to get the Format utils and ResponseBuilder for these formats.
  • Breaking change: Response builders are now moved into the io.fintrospect.formats.<format> packages.
  • Breaking change: rename of to ArgoUtil and ArgoJsonResponseBuilder which are now Argo.JsonFormat and Argo.ResponseBuilder respectively. This structure is now is unified with the other JSON formats.


  • Please ignore this release and go straight to v9.0.1


  • Bugfix for Body models not being outputted in Swagger 2 JSON schema.


  • Added optional description field to RouteSpec. This appears as the "implementation notes" section in Swagger docs.


  • Upgraded version of Finagle that we build against to v6.27.0.
  • Bugfix for Path parameter values not being encoded correctly in clients.


  • Added native XML support as a body and a parameter type.


  • Bugfix for cannot bind custom body to a request.


  • Unification of Server and Client route description APIs. Breaking API changes (renames only):
    • DescribedRoute is now RouteSpec
    • ClientRoute is now RouteSpec (different package), and bindTo() is now bindToClient()
    • Route is now ServerRoute
    • Client is now RouteClient
    • ResponseWithExample is now ResponseSpec
    • Methods on Request/Response have dropped the get prefix. Get getUri -> uri


  • Support for multi-parameters in forms and queries to provide type-safe retrieval. Eg. Query.required.*.int("name")
  • Removal of some generics around Parameters. Should be non-breaking change.


  • Upgraded version of Finagle that we build against to v6.26.0


  • Unfortunately contains a bug in the new Client code. Please ignore this release and upgrade to latest.

v6.1.X -> v7.X.X

  • Custom parameter support now more modular. Breaking change of custom(XXX) -> apply(XXX) in Parameters classes, which requires using ParameterSpec instead of arg list.
  • Improved support for Forms and custom Body types (other than JSON). Dropped support for Forms parameters as request params and reimplemented as a particular Body type, with automatic setting of Content-Type headers. Clients will need to migrate to the new Form format (see examples).
  • Body parameters are now parsed for validity in the same way as other required parameters.
  • EXPERIMENTAL! Ability to define clients using the same style API as the Services. Supports Path/Query/Headers, but not Bodies or Forms as yet.

v5.X.X -> v6.X.X

  • We've got a domain! So... repackage from io.github.daviddenton.fintrospect to io.fintrospect. A global search and replace on your codebase will do it.
  • Added support for custom parameter types. See the example code]).

v4.X.X -> v5.X.X

  • Upgrade to require Java 8 time API for time parameter support.
  • Removal of Joda-time dependencies since you can now just use java.time instead.
  • Collapsed DescriptionRenderer into ModuleRenderer, so just one trait to implement to provide custom format support.
  • Ability to override the default location of the description route.

v3.X.X -> v4.X.X

  • Addition of custom response rendering formats. See the example code]. Modules now require a fully configured ModuleRenderer upon instantiation, which provides not just the rendering of the Documentation (ie. the old Renderer which is now DescriptionRenderer), but also the format of error messages. Some repackaging of the pluggable renderers has occurred.
  • ResponseBuilder is now generic superclass of pluggable formats. Json support has moved to JsonResponseBuilder, so changes to your code will be required to support this.
  • Renamed Identification Header to X-Fintrospect-Route-Name
  • Added ability to apply filters to all custom routes in a module (apart from the description route, which is NOT affected)

v2.X.X -> v3.X.X

Migrated away from the in-built Twitter HTTP Request package (com.twitter.finagle.http) and onto the Netty org.jboss.netty.handler.codec.http.Request. This is to provide compatibility with the changes to the Finagle APIs in regards to creating both servers and clients. It also has the advantage of unifying the client/server interface (previously it was different between the two). The only things that should have to change in your code are:

  • How servers are created - the new method is simpler (see the example code].
  • The signature of routes is now Service[Request,Response]. Since the Twitter Request/Response classes extends these interfaces, usages of the ResponseBuilder remain the same.
  • Form-based parameters are now defined with the Form object, and not the Query object (which now just retrieves Query String parameters from the URL).