Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/lispyclouds/navi
A tiny, data-driven library converting OpenAPI spec to Reitit routes.
https://github.com/lispyclouds/navi
api clojure data-driven openapi rest-api swagger
Last synced: 2 days ago
JSON representation
A tiny, data-driven library converting OpenAPI spec to Reitit routes.
- Host: GitHub
- URL: https://github.com/lispyclouds/navi
- Owner: lispyclouds
- License: mit
- Created: 2021-03-08T13:24:13.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2024-10-19T11:28:57.000Z (2 months ago)
- Last Synced: 2024-12-16T00:06:42.054Z (9 days ago)
- Topics: api, clojure, data-driven, openapi, rest-api, swagger
- Language: Clojure
- Homepage:
- Size: 54.7 KB
- Stars: 56
- Watchers: 4
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# navi [![Tests](https://github.com/lispyclouds/navi/actions/workflows/ci.yaml/badge.svg)](https://github.com/lispyclouds/navi/actions/workflows/ci.yaml)
A tiny library converting [OpenAPI](https://www.openapis.org/) route definitions to [Reitit](https://cljdoc.org/jump/release/metosin/reitit) routes.
Suitable for [spec-first](https://www.atlassian.com/blog/technology/spec-first-api-development) servers.
## Features
- Read OpenAPI 3 definitions as JSON or YAML
- Remote and relative [refs](https://swagger.io/docs/specification/using-ref/)
- Request and response coercions powered by [Malli](https://github.com/metosin/malli)
- requestBody coercion
- Strings with uuid and pattern types
- A large subset of OpenAPI types are currently supported, please raise an issue if something is unsupportedCurrently unsupported:
- Other coercion libsAny contributions are much much welcome and appreciated!
## Installation
Leiningen/Boot
```clojure
[org.clojars.lispyclouds/navi "0.0.10"]
```Clojure CLI/deps.edn
```clojure
{org.clojars.lispyclouds/navi {:mvn/version "0.0.10"}}
```Gradle
```groovy
compile 'org.clojars.lispyclouds:navi:0.0.10'
```Maven
```xmlorg.clojars.lispyclouds
navi
0.0.10```
## Usage
Given a `api.yaml`:
```yaml
openapi: "3.0.0"info:
title: My calculator
version: "0.1.0"
description: My awesome calc!paths:
"/add/{n1}/{n2}":
get:
operationId: AddGet
summary: Adds two numbersparameters:
- name: n1
required: true
in: path
description: The first number
schema:
type: integer
- name: n2
required: true
in: path
description: The second number
schema:
type: integer
post:
operationId: AddPost
summary: Adds two numbers via POSTrequestBody:
description: The numebers map
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/NumbersMap"
"/health":
get:
operationId: HealthCheck
summary: Returns Ok if all is wellcomponents:
schemas:
NumbersMap:
type: object
required:
- n1
- n2
properties:
n1:
type: integer
description: The first number
n2:
type: integer
description: The second number
```A clojure map of OperationId to handler fns:
```clojure
(def handlers
{"AddGet" (fn [{{{:keys [n1 n2]} :path} :parameters}]
{:status 200
:body (str (+ n1 n2))})
"AddPost" (fn [{{{:keys [n1 n2]} :body} :parameters}]
{:status 200
:body (str (+ n1 n2))})
"HealthCheck" (fn [_]
{:status 200
:body "Ok"})})
```Generate the routes:
```clojure
(require '[navi.core :as navi])(navi/routes-from (slurp "api.yaml") handlers)
=>
[["/add/{n1}/{n2}"
{:get
{:handler #function[navi.core/fn--8260],
:parameters
{:path
[:map
[:n1 #function[clojure.core/int?]]
[:n2 #function[clojure.core/int?]]]}},
:post
{:handler #function[navi.core/fn--8266],
:parameters
{:body
[:map
{:closed false}
[:n1 #function[clojure.core/int?]]
[:n2 #function[clojure.core/int?]]]}}}]
["/health" {:get {:handler #function[navi.core/fn--8271]}}]]
```Bootstrapping a Jetty server:
```clojure
(ns server.main
(:require
[muuntaja.core :as m]
[navi.core :as navi]
[reitit.coercion.malli :as malli]
[reitit.http :as http]
[reitit.http.coercion :as coercion]
[reitit.http.interceptors.exception :as exception]
[reitit.http.interceptors.muuntaja :as muuntaja]
[reitit.http.interceptors.parameters :as parameters]
[reitit.interceptor.sieppari :as sieppari]
[reitit.ring :as ring]
[ring.adapter.jetty :as jetty])
(:gen-class))(def server
(http/ring-handler
(http/router (-> "api.yaml"
slurp
(navi/routes-from handlers)) ; handlers is the map described before
{:data {:coercion malli/coercion
:muuntaja m/instance
:interceptors [(parameters/parameters-interceptor)
(muuntaja/format-negotiate-interceptor)
(muuntaja/format-response-interceptor)
(exception/exception-interceptor)
(muuntaja/format-request-interceptor)
(coercion/coerce-exceptions-interceptor)
(coercion/coerce-response-interceptor)
(coercion/coerce-request-interceptor)]}})
(ring/routes
(ring/create-default-handler
{:not-found (constantly {:status 404
:headers {"Content-Type" "application/json"}
:body "{\"message\": \"Took a wrong turn?\"}"})}))
{:executor sieppari/executor}))(defn -main
[& _]
(jetty/run-jetty (var server)
{:host "0.0.0.0"
:port 7777
:join? false
:async? true}))
```deps.edn used for this example:
```edn
{:deps {org.clojars.lispyclouds/navi {:mvn/version "0.0.10"}
metosin/reitit-core {:mvn/version "0.6.0"}
metosin/reitit-http {:mvn/version "0.6.0"}
metosin/reitit-interceptors {:mvn/version "0.6.0"}
metosin/reitit-malli {:mvn/version "0.6.0"}
metosin/reitit-ring {:mvn/version "0.6.0"}
metosin/reitit-sieppari {:mvn/version "0.6.0"}
metosin/muuntaja {:mvn/version "0.6.8"}
ring/ring-jetty-adapter {:mvn/version "1.9.6"}}}
```### Build Requirements
- JDK 8+
- Clojure [tools.deps](https://clojure.org/guides/getting_started)### Running tests locally
- `clojure -X:test` to run all tests## License
Copyright © 2020- Rahul De
Distributed under the MIT License. See LICENSE.