
He who controls access between the two, deciding who and what can pass through
Legba is a library designed for building fully OpenAPI 3.1 compliant services in Clojure.
Legba streamlines the creation of OpenAPI based servers by emphasizing the OpenAPI schema file as the foundation of your service definition. Unlike other libraries that generate the schema from routes & validation defined in a separate DSL, Legba takes a different approach: it uses your OpenAPI schema to create the necessary routes and wraps your supplied handlers with OpenAPI validation.
Legba ensures that the final OpenAPI file exposed to your users remains unrestricted, reviewable, and editable.
-
Provide rock solid, full coverage of OpenAPI 3.1 spec
-
Support all the bells & whistles such as
$refs
, conditionals, etc -
Great performance, being built on networknt/json-schema-validator, which consistently ranks on the top of the java based json-schema validators for both performance and correctness.
-
Be server adapter agnostic, it should be usable with any RING compliant server adapter (jetty, http-kit, aleph, hirundo, etc...)
-
Provide building blocks to build on top of your preferred routing libraries or plug onto any existing router
-
But can also provide a default, easy to use single handler entry point with routing for a given schema, built on the aforementioned primitives
-
Provide detailed, informative and customizable error messages
-
Defaults to https://datatracker.ietf.org/doc/html/rfc9457 for error formatting
-
Works with both JSON and YAML OpenAPI schemas
You can either:
-
Either use
s-exp.legba.handler/handlers
: taking an OpenAPI file and a map of[method path]
->handler
, it will return a new map of[method path]
->handler
, with all handlers wrapped with an OpenAPI validation middleware. From this map you can then plug the OpenAPI handlers in any routing solution and compose as you prefer. -
Or use
s-exp.legba/routing-handler
: taking an OpenAPI file and a map of[method path]
->handler
that matches the routes of the OpenAPI schema, returns a single handler that will manage routing and perform validation and marshaling of the data according to the schema (via networknt/json-schema-validator). This handler can simply be plugged to a RING server adapter and you're good to go.
Examples:
[:get "/items"]
[:get "/item/{itemId}"] ;; Path parameter
[:post "/items"]
[:delete "/user/{userId}/role/{roleId}"] ;; Multiple params
[:get "/assets/*"] ;; Prefix matching
Route Syntax Rules:
http-method
is a keyword: e.g.:get
,:put
,:patch
, etc.path
is a string using{param}
for path parameters—matching OpenAPI.- All path parameters will be extracted and made available in the request under
:path-params
(default, configurable). - You can define routes with multiple or nested parameters:
/foo/{id}/bar/{otherId}
- You can define routes with prefixes such as
/foo/bar/*
, in which case any request starting with/foo/bar/
will be accepted. - Additional static or catch-all routes can be added via the
:extra-routes
option (for custom needs outside of the OpenAPI schema).
Or via git deps:
com.s-exp/legba {:git/url "https://github.com/mpenet/legba.git" :git/sha "..."}
/!\
Please note that this is still an alpha release. While it is fairly stable and I make an effort to maintain API contracts, some aspects are still under development. I reserve the right to make changes until the alpha tag is removed.
(require '[s-exp.legba :as l])
(l/routing-handler {[:get "/item/{itemId}"]
(fn [_request]
{...})
[:get "/items"]
(fn [_request]
{...})
[:get "/search"]
(fn [_request]
{...})
[:post "/items"]
(fn [_request]
{..})}
"classpath://schema/oas/3.1/catalog.json"
;; {...} ; options
)
There's also an extra argument with options:
-
:not-found-response
- defaults to{:status 404 :body "Not found"}
-
:key-fn
- Control map keys decoding when turning jackson JsonNodes to clj data for the handler - default tokeyword
-
:query-string-params-key
- where to find the decoded query-string parameters - defaults to:query-params
-
:validation-result
- function that controls how to turncom.networknt.schema.ValidationResult
into a clj -> json response. Defaults tos-exp.legba.schema/validation-result
-
:extra-routes
- extra routes to be passed to the underlying router -
:path-params-key
- where to locate the routing extracted path parameters - Defaults to:path-params
-
soft-response-validation
- boolean, if true response validation doesn't throw and assocs the error on the ring response as response-validation-error. -
rfc9457-type-fn
- defaults tos-exp.legba.middleware/ex->rfc9457-type
- return rfc9457 error type to be used in json+problem payloads from an exception.
-
You don't have to do any JSON marshaling, if the content-type is of application/json type we will read data as such, same goes for writing. Given the validation library needs the data to be parsed, we preserve this work and re-use the parsed content.
-
ring.middleware.params/wrap-params
is applied to the incoming request as to allow path params matching for validation.
Using s-exp.legba.json-schema you can also perform standalone json-schema validation.
Define a simple JSON schema file json-schema.json
{"type" "object"
"properties" {"name" {"type" "string"}
"age" {"type" "integer"}}
"required" ["name" "age"]
"additionalProperties" false}
(require '[s-exp.legba.json-schema :as json-schema]
;; Validate the data
(-> (json-schema/schema "classpath://json-schema.json")
(json-schema/validate! "{\"name\":\"Alice\",\"age\":30}"))
Legba provides utilities for OpenAPI Overlay via s-exp.legba.overlay
.
This allows you to dynamically update or remove parts of your OpenAPI schema using overlay instructions, making it easy to tailor or extend schemas programmatically.
- The core function is
s-exp.legba.overlay/apply
:- Takes an OpenAPI schema (as a JSON string) and overlay instructions (as a JSON string).
- Applies update/remove actions as per the overlay specification, returning the modified schema.
(require '[s-exp.legba.overlay :as overlay])
(def openapi-schema
(slurp "path/to/openapi.json"))
(def overlay-json
"{\"actions\": [
{\"target\": \"$..['x-private']\", \"remove\": true}
]}")
;; Returns updated schema JSON string with actions applied
(overlay/apply openapi-schema overlay-json)
This can be useful for customizing schemas for different consumers, removing internal fields, or overlaying additional information as needed.
Copyright © 2024-2025 Max Penet
Distributed under the Eclipse Public License version 1.0.