{"id":15012953,"url":"https://github.com/metosin/ring-swagger","last_synced_at":"2025-05-15T08:05:06.329Z","repository":{"id":13711806,"uuid":"16405796","full_name":"metosin/ring-swagger","owner":"metosin","description":"Swagger Spec for Clojure Web Apps","archived":false,"fork":false,"pushed_at":"2024-07-09T20:35:03.000Z","size":1458,"stargazers_count":373,"open_issues_count":17,"forks_count":84,"subscribers_count":26,"default_branch":"master","last_synced_at":"2025-05-14T00:24:53.268Z","etag":null,"topics":["clojure","json-schema","metosin-stable","openapi","rest","schema-elements","swagger"],"latest_commit_sha":null,"homepage":"http://metosin.github.io/ring-swagger/doc/","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/metosin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-01-31T11:03:45.000Z","updated_at":"2025-05-13T04:29:24.000Z","dependencies_parsed_at":"2024-04-23T05:40:45.686Z","dependency_job_id":"8dd4da38-81b9-4c03-ab81-462e7ce161b2","html_url":"https://github.com/metosin/ring-swagger","commit_stats":{"total_commits":921,"total_committers":40,"mean_commits":23.025,"dds":0.3626492942453855,"last_synced_commit":"612685336a7265f820dc6dd362ef300adcbc1977"},"previous_names":[],"tags_count":69,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metosin%2Fring-swagger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metosin%2Fring-swagger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metosin%2Fring-swagger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metosin%2Fring-swagger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/metosin","download_url":"https://codeload.github.com/metosin/ring-swagger/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254059457,"owners_count":22007761,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","json-schema","metosin-stable","openapi","rest","schema-elements","swagger"],"created_at":"2024-09-24T19:43:30.576Z","updated_at":"2025-05-15T08:05:06.262Z","avatar_url":"https://github.com/metosin.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ring-Swagger [![Build Status](https://travis-ci.org/metosin/ring-swagger.svg?branch=master)](https://travis-ci.org/metosin/ring-swagger) [![Downloads](https://versions.deps.co/metosin/ring-swagger/downloads.svg)](https://versions.deps.co/metosin/ring-swagger)\n\n[Swagger](http://swagger.io/) 2.0 implementation for Clojure/Ring using [Plumatic Schema](https://github.com/Plumatic/schema) (support for [clojure.spec](http://clojure.org/about/spec) via [spec-tools](https://github.com/metosin/spec-tools)).\n\n- Transforms deeply nested Schemas into Swagger JSON Schema definitions\n- Extended \u0026 symmetric JSON \u0026 String serialization \u0026 coercion\n- Middleware for handling Schemas Validation Errors \u0026 Publishing swagger-data\n- Local api validator\n- Swagger artifact generation\n  - [swagger.json](https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#specification) via `ring.swagger.swagger2/swagger-json`\n  - [Swagger UI](https://github.com/swagger-api/swagger-ui) bindings. (get the UI separately as [jar](https://github.com/metosin/ring-swagger-ui) or from [NPM](https://www.npmjs.com/package/swagger-ui))\n\n## Latest version\n\n[![Clojars Project](http://clojars.org/metosin/ring-swagger/latest-version.svg)](http://clojars.org/metosin/ring-swagger)\n\nThe [CHANGELOG](https://github.com/metosin/ring-swagger/blob/master/CHANGELOG.md).\n\nRequires Java 1.8+\n\n## Web libs using Ring-Swagger\n\n- [Compojure-Api](https://github.com/metosin/compojure-api) for Compojure\n- [fnhouse-swagger](https://github.com/metosin/fnhouse-swagger) for fnhouse\n- [route-swagger](https://github.com/frankiesardo/route-swagger) for Pedestal\n- [yada](https://github.com/juxt/yada)\n- [kekkonen](https://github.com/metosin/kekkonen)\n\n## Getting help\n\n[Clojurians slack](https://clojurians.slack.com/) ([join](http://clojurians.net/)) has a channel [#ring-swagger](https://clojurians.slack.com/messages/ring-swagger/) for Ring-swagger related issues. You can also ask questions about Ring-swagger on other channels at Clojurians Slack or at #clojure on Freenode IRC (mention or `ring-swagger` to highlight us).\n\n## Info\n\nRoute definitions are expected as a clojure Map defined by the Schema [Contract](https://github.com/metosin/ring-swagger/blob/master/src/ring/swagger/swagger2_schema.clj).\nThe Schema allows mostly any extra keys as ring-swagger tries not to be on your way - one can pass any  valid Swagger spec data in.\n\n[API Docs](http://metosin.github.io/ring-swagger/doc/).\n\n### Simplest possible example\n\n```clojure\n(require '[ring.swagger.swagger2 :as rs])\n\n(rs/swagger-json {})\n\n; {:swagger \"2.0\",\n;  :info {:title \"Swagger API\", :version \"0.0.1\"},\n;  :produces [\"application/json\"],\n;  :consumes [\"application/json\"],\n;  :paths {},\n;  :definitions {}}\n```\n\n### More complete example\n\nInfo, tags, routes and anonymous nested schemas.\n\n```clojure\n(require '[schema.core :as s])\n\n(s/defschema User {:id s/Str,\n                   :name s/Str\n                   :address {:street s/Str\n                             :city (s/enum :tre :hki)}})\n\n(s/with-fn-validation\n  (rs/swagger-json\n    {:info {:version \"1.0.0\"\n            :title \"Sausages\"\n            :description \"Sausage description\"\n            :termsOfService \"http://helloreverb.com/terms/\"\n            :contact {:name \"My API Team\"\n                      :email \"foo@example.com\"\n                      :url \"http://www.metosin.fi\"}\n            :license {:name \"Eclipse Public License\"\n                      :url \"http://www.eclipse.org/legal/epl-v10.html\"}}\n     :tags [{:name \"user\"\n             :description \"User stuff\"}]\n     :paths {\"/api/ping\" {:get {}}\n             \"/user/:id\" {:post {:summary \"User Api\"\n                                  :description \"User Api description\"\n                                  :tags [\"user\"]\n                                  :parameters {:path {:id s/Str}\n                                               :body User}\n                                  :responses {200 {:schema User\n                                                   :description \"Found it!\"}\n                                              404 {:description \"Ohnoes.\"}}}}}}))\n\n; {:swagger \"2.0\",\n;  :info {:title \"Sausages\",\n;         :version \"1.0.0\",\n;         :description \"Sausage description\",\n;         :termsOfService \"http://helloreverb.com/terms/\",\n;         :contact {:name \"My API Team\",\n;                   :email \"foo@example.com\",\n;                   :url \"http://www.metosin.fi\"},\n;         :license {:name \"Eclipse Public License\",\n;                   :url \"http://www.eclipse.org/legal/epl-v10.html\"}},\n;  :produces [\"application/json\"],\n;  :consumes [\"application/json\"],\n;  :tags [{:name \"user\", :description \"User stuff\"}],\n;  :paths {\"/api/ping\" {:get {:responses {:default {:description \"\"}}}},\n;          \"/user/{id}\" {:post {:summary \"User Api\",\n;                               :description \"User Api description\",\n;                               :tags [\"user\"],\n;                               :parameters [{:in \"path\",\n;                                             :name \"id\",\n;                                             :description \"\",\n;                                             :required true,\n;                                             :type \"string\"}\n;                                            {:in \"body\",\n;                                             :name \"User\",\n;                                             :description \"\",\n;                                             :required true,\n;                                             :schema {:$ref \"#/definitions/User\"}}],\n;                               :responses {200 {:schema {:$ref \"#/definitions/User\"},\n;                                                         :description \"Found it!\"},\n;                                           404 {:description \"Ohnoes.\"}}}}},\n;  :definitions {\"User\" {:type \"object\",\n;                        :properties {:id {:type \"string\"},\n;                                     :name {:type \"string\"},\n;                                     :address {:$ref \"#/definitions/UserAddress\"}},\n;                        :additionalProperties false,\n;                        :required (:id :name :address)},\n;                \"UserAddress\" {:type \"object\",\n;                               :properties {:street {:type \"string\"},\n;                                                     :city {:type \"string\",\n;                                                            :enum (:tre :hki)}},\n;                               :additionalProperties false,\n;                               :required (:street :city)}}}\n```\n\nproducing the following ui:\n\n![ring-swagger](https://raw.githubusercontent.com/wiki/metosin/ring-swagger/ring-swagger.png)\n\n## Customizing Swagger Spec output\n\nOne can pass extra options-map as a third parameter to `swagger-json`. The following options are available:\n\n```clojure\n :ignore-missing-mappings?        - (false) boolean whether to silently ignore\n                                    missing schema to JSON Schema mappings. if\n                                    set to false, IllegalArgumentException is\n                                    thrown if a Schema can't be presented as\n                                    JSON Schema.\n\n :default-response-description-fn - ((constantly \"\")) - a fn to generate default\n                                    response descriptions from http status code.\n                                    Takes a status code (Int) and returns a String.\n\n :handle-duplicate-schemas-fn     - (ring.swagger.core/ignore-duplicate-schemas),\n                                    a function to handle possible duplicate schema\n                                    definitions. Takes schema-name and set of found\n                                    attached schema values as parameters. Returns\n                                    sequence of schema-name and selected schema value.\n\n :collection-format               - Sets the collectionFormat for query and formData\n                                    parameters.\n                                    Possible values: multi, ssv, csv, tsv, pipes.\"\n```\n\nFor example, to get default response descriptions from the [HTTP Spec](http://en.wikipedia.org/wiki/List_of_HTTP_status_codes),\nyou can do the following:\n\n```clojure\n(require '[ring.util.http-status :as status])\n\n(rs/swagger-json\n  {:paths {\"/hello\" {:post {:responses {200 nil\n                                        425 nil\n                                        500 {:description \"FAIL\"}}}}}}\n  {:default-response-description-fn status/get-description})\n\n; {:swagger \"2.0\"\n;  :info {:title \"Swagger API\" :version \"0.0.1\"}\n;  :consumes [\"application/json\"]\n;  :produces [\"application/json\"]\n;  :definitions {}\n;  :paths {\"/hello\" {:post {:responses {200 {:description \"OK\"}\n;                                       425 {:description \"The collection is unordered.\"}\n;                                       500 {:description \"FAIL\"}}}}}}\n```\n\n## Validating the Swagger Spec\n\nThe generated full spec can be validated against the [Swagger JSON Schema](https://raw.githubusercontent.com/reverb/swagger-spec/master/schemas/v2.0/schema.json)\nwith the help of [scjsv](https://github.com/metosin/scjsv).\n\n```clojure\n(require '[ring.swagger.validator :as v])\n\n(v/validate (rs/swagger-json {:paths {\"/api/ping\" {:get nil}}}))\n; nil\n\n(v/validate (rs/swagger-json {:pathz {\"/api/ping\" {:get nil}}}))\n; ({:level \"error\"\n;   :schema {:loadingURI \"#\", :pointer \"\"}\n;   :instance {:pointer \"\"}\n;   :domain \"validation\"\n;   :keyword \"additionalProperties\"\n;   :message \"object instance has properties which are not allowed by the schema: [\\\"pathz\\\"]\", :unwanted [\"pathz\"]})\n```\n\nFor more information about creating your own adapter, see [Collecting API Documentation](https://github.com/metosin/ring-swagger/wiki/Collecting-API-Documentation).\n\n## Transforming the Swagger Spec\n\nThere are the following utility functions for transforming the spec (on the client side):\n\n`ring.swagger.swagger2/transform-operations` - transforms the operations under the :paths of a ring-swagger spec\nby applying `(f operation)` to all operations. If the function returns nil, the given operation is removed.\n\nAs an example, one can filter away all operations with `:x-no-doc` set to `true`:\n\n```clojure\n(defn remove-x-no-doc [endpoint]\n  (if-not (some-\u003e endpoint :x-no-doc true?)\n    endpoint))\n\n(transform-operations remove-x-no-doc {:paths {\"/a\" {:get {:x-no-doc true}, :post {}}\n                                               \"/b\" {:put {:x-no-doc true}}}}))\n; {:paths {\"/a\" {:post {}}}}\n```\n\n## Web Schemas\n\n[Prismatic Schema](https://github.com/Prismatic/schema) is used to describe both the input \u0026 output schemas for routes.\n\nAs Swagger 2.0 Spec Schema is a deterministic subset of JSON Schema, so not all Clojure Schema elements can be used.\n\n### Schema to Swagger JSON Schema conversion\n\nThere are two possible methods to do this:\n\n1. class-based dispatch via `ring.swagger.json-schema/convert-class`.\n2. protocol-based dispatch via `ring.swagger.json-schema/JsonSchema` - the `convert` fn.\n\nBoth take the Schema and swagger options map as arguments. Options contain also `:in` to denote the possible location\nof the schema (`nil`, `:query`, `:header`, `:path`, `:formData` and `:body`).\n\nTo support truly symmetric web schemas, one needs also to ensure both JSON Serialization and\ndeserialization/coercion from JSON.\n\n### Class-based dispatch\n\n```clojure\n(require '[ring.swagger.json-schema :as json-schema])\n\n(defmethod json-schema/convert-class java.sql.Date [_ _] {:type \"string\" :format \"date\"})\n```\n\n#### Protocol-based dispatch\n\n```clojure\n(require '[ring.swagger.json-schema :as json-schema])\n\n(extend-type java.util.regex.Pattern\n  json-schema/JsonSchema\n  (json-schema/convert [e _]\n    {:type \"string\" :pattern (str e)}))\n```\n\nOne can also use the options to create more accurate specs (via the `:in` option).\n\n```clojure\n(extend-type schema.core.Maybe\n  json-schema/JsonSchema\n  (convert [e {:keys [in]}]\n    (let [schema (-\u003eswagger (:schema e))]\n      (if (#{:query :formData} in)\n        (assoc schema :allowEmptyValue true)\n        schema))))\n```\n\n### Out-of-the-box supported Schema elements\n\n| Clojure Schema                              | JSON Schema              | Sample JSON |\n| --------------------------------------------|--------------------------|:-----------:|\n| `Integer`                                   | integer, int32           | `1`\n| `Long`, `s/Int`                             | integer, int64           | `1`\n| `Double`, `Number`, `s/Num`                 | number, double           | `1.2`\n| `String`, `s/Str`, `Keyword`, `s/Keyword`, `Symbol`, `s/Symbol`, `s/Any` non-body-parameter | string                   | `\"kikka\"`\n| `Boolean`                                   | boolean                  | `true`\n| `nil`, `s/Any` body-parameter            | void                     |\n| `java.util.regex.Pattern`,                  | string, regex            | `[a-z0-9]`\n| `#\"[a-z0-9]+\"`                              | string, pattern          | `\"a6\"`\n| `s/Uuid`, `java.util.UUID`                  | string, uuid             | `\"77e70512-1337-dead-beef-0123456789ab\"`\n| `java.util.Date`, `org.joda.time.DateTime`, `s/Inst`, `java.time.Instant` | string, date-time        | `\"2014-02-18T18:25:37.456Z\"`, also without millis: `\"2014-02-18T18:25:37Z\"`\n| `org.joda.time.LocalDate`, `java.time.LocalDate` | string, date             | `\"2014-02-19\"`\n| `org.joda.time.LocalTime`, `java.time.LocalTime` | string, time             | `\"16:22\"`\n| `(s/enum X Y Z)`                            | *type of X*, enum(X,Y,Z)\n| `(s/maybe X)`                               | *type of X*\n| `(s/both X Y Z)`                            | *type of X*\n| `(s/constrained X pred)`                    | *type of X*\n| `(s/conditional p1 X p2 Y p3 Z)`            | *one of type X, Y, Z*\n| `(s/cond-pre X Y Z)`                        | *one of type X, Y, Z*\n| `(s/either X Y Z)`                          | *type of X*\n| `(s/named X name)`                          | *type of X*\n| `(s/one X name)`                            | *type of X*\n| `(s/recursive Var)`                         | *Ref to (model) Var*\n| `(s/eq X)`                                  | *type of class of X*, enum(X)\n| `(s/optional-key X)`                        | *optional key*\n| `(s/required-key X)`                        | *required key*\n| `s/Keyword` (as a key)                      | *ignored*\n\n- All supported types have symmetric JSON serialization (Cheshire encoders) \u0026 deserialization (Schema coercions)\n- Vectors, Sets and Maps can be used as containers\n- Maps are presented as Complex Types and References. Model references are resolved automatically.\n  - Nested maps are transformed automatically into flat maps with generated child references\n  - Maps can be within valid containers (as only element - heterogeneous schema sequences not supported by the spec)\n\n### Missing Schema elements\n\nIf Ring-swagger can't transform the Schemas into JSON Schemas, by default a `IllegalArgumentException` will be thrown.\nSetting the `:ignore-missing-mappings?` to `true` causes the errors to be ignored - missing schema elements will be\nignored from the generated Swagger schema.\n\n### Body and Response model names\n\nStandard Prismatic Schema names are used. Nested schemas are traversed and all found sub-schemas are named\nautomatically - so that they can be referenced in the generated Swagger spec.\n\nSwagger 2.0 squashes all api models into a single global namespace, so schema name collisions can happen.\nWhen this happens, the function defined by `:handle-duplicate-schemas-fn` option is called to resolve the collision.\nBy default, the collisions are ignored.\n\nOne accidental reason for schema name collisions is the use of normal `clojure.core` functions to create transformed\ncopies of the schemas. The normal core functions retain the original schema meta-data and by so the schema name.\n\n```clojure\n(s/defschema User {:id s/Str, :name s/Str})\n(def NewUser (dissoc User :id)) ; dissoc does not remove the schema meta-data\n\n(meta User)\n; {:name User :ns user}\n\n\n(meta NewUser)\n; {:name User :ns user} \u003c--- fail, now there are two User-schemas around.\n```\n\nThere are better schema transformers functions available at [schema-tools](https://github.com/metosin/schema-tools).\nIt's an implicit dependency of ring-swagger.\n\n### Extra Schema elements supported by `ring.swagger.json-schema-dirty`\n\nSome Schema elements are impossible to accurately describe within boundaries of JSON-Schema or Swagger spec.\nYou can require `ring.swagger.json-schema-dirty` namespace to get JSON Schema dispatching for the following:\n\n**WARNING** Swagger-UI might not display these correctly and the code generated by swagger-codegen will be inaccurate.\n\n| Clojure | JSON Schema | Sample  |\n| --------|-------|:------------:|\n| `(s/conditional pred X pred Y pred Z)` | x-oneOf: *type of X*, *type of Y*, *type of Z*\n| `(s/if pred X Y)` | x-oneOf: *type of X*, *type of Y*\n\n### Schema coercion\n\nRing-swagger uses [Schema coercions](http://plumatic.github.io/schema-0-2-0-back-with-clojurescript-data-coercion)\nfor transforming the input data into vanilla Clojure and back.\n\nThere are two coercers in `ring.swagger.coerce`, the `json-schema-coercion-matcher` and `query-schema-coercion-matcher`.\nThese are enchanced versions of the original Schema coercers, adding support for all the supported Schema elements,\nincluding Dates \u0026 Regexps.\n\n#### Custom Coercions\n\nIn order to allow for custom input coercion, ring-swagger includes a multimethod 'custom-matcher' that can be implemented for custom input types. For example, to coerce currency strings into joda.money.Money objects, you can implement the following:\n\n```clojure\n(require '[ring.swagger.coerce :as coerce])\n(import org.joda.money.Money)\n\n(defmethod coerce/custom-matcher org.joda.money.Money  [_]  #(org.joda.money.Money/parse %))\n```\n\nThis will allow org.joda.money.Money objects in your Schema definitions to be coerced correctly. However, this is only for coercing input, see [Schema to Swagger JSON Schema conversion](#schema-to-swagger-json-schema-conversion) for examples on transforming output.\n\n#### Coerce!\n\nRing-swagger provides a convenience function for coercion, `ring.swagger.schema/coerce!`. It returns either a valid\ncoerced value of slingshots an Map with type `:ring.swagger.schema/validation`. One can catch these exceptions via\n`ring.swagger.middleware/wrap-validation-errors` and return a JSON-friendly map of the contents.\n\n```clojure\n(require '[schema.core :as s])\n(require '[ring.swagger.schema :refer [coerce!]])\n\n(s/defschema Bone {:size Long, :animal (s/enum :cow :tyrannosaurus)})\n\n(coerce! Bone {:size 12, :animal \"cow\"})\n; {:animal :cow, :size 12}\n\n(coerce! Bone {:animal :sheep})\n; ExceptionInfo throw+: #schema.utils.ErrorContainer{:error {:animal (not (#{:tyrannosaurus :cow} :sheep)), :size missing-required-key}, :type :ring.swagger.schema/validation}  ring.swagger.schema/coerce! (schema.clj:57)\n```\n\n## Adding description to Schemas\n\nOne can add extra meta-data, including descriptions to schema elements using `ring.swagger.json-schema/field` and `ring.swagger.json-schema/describe` functions. These work by adding meta-data to schema under `:json-schema`-key. Objects which don't natively support meta-data, like Java classes, are wrapped automatically into `ring.swagger.json-schema/FieldSchema` to enable the meta-data.\n\n### Example\n\n```clojure\n(require '[schema.core :as s])\n(require '[ring.swagger.schema :as rs])\n(require '[ring.swagger.json-schema :as rjs])\n\n(s/defschema Required\n  (rjs/field\n    {(s/optional-key :name) s/Str\n     (s/optional-key :title) s/Str\n     :address (rjs/field\n                {:street (rsjs/field s/Str {:description \"description here\"})}\n                {:description \"Streename\"\n                 :example \"Ankkalinna 1\"})}\n    {:minProperties 1\n     :description \"I'm required\"\n     :example {:name \"Iines\"\n               :title \"Ankka\"}}))\n\n; produces the following JSON Schema models =\u003e\n;\n; {\"Required\" {:type \"object\"\n;              :description \"I'm required\"\n;              :example {:name \"Iines\"\n;                        :title \"Ankka\"}\n;              :minProperties 1\n;              :required [:address]\n;              :properties {:name {:type \"string\"}\n;                           :title {:type \"string\"}\n;                           :address {:$ref \"#/definitions/RequiredAddress\"}}\n;              :additionalProperties false}\n;  \"RequiredAddress\" {:type \"object\"\n;                     :description \"Streename\"\n;                     :example \"Ankkalinna 1\"\n;                     :properties {:street {:type \"string\"\n;                                           :description \"description here\"}}\n;                     :required [:street]\n;                     :additionalProperties false}}\n```\n\n## Release process\n\nTo release a version, set the project.clj version to the one you want to release, but with a `-SNAPSHOT` suffix.\n\nThen create a commit reading \"Release :{major,minor,patch,alpha,beta,rc}\" based on whether\nyou want the next development version to be a major/minor/patch/alpha/beta/rc increment.\n\nPush to master, and the GitHub Actions release will release the jar to clojars, then bump the version\non the master branch.\n\n## License\n\nCopyright © 2014-2018 [Metosin Oy](http://www.metosin.fi)\n\nDistributed under the Eclipse Public License, the same as Clojure.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetosin%2Fring-swagger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmetosin%2Fring-swagger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetosin%2Fring-swagger/lists"}