From 24ffe6449a545102748144f6a1819b2a09b1b1e6 Mon Sep 17 00:00:00 2001 From: Rajkumar Natarajan Date: Tue, 22 Jul 2025 12:57:12 -0700 Subject: [PATCH 1/2] fix reflection and update readme --- README.md | 90 +++++++++++++++++++++++++++++++++-- src/ring/swagger/openapi3.clj | 4 +- 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1a9ad8c..0ab3f85 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 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) -[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)). +[Swagger](http://swagger.io/) 2.0/[OpenApi](https://spec.openapis.org/oas/v3.0.3.html) 3.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)). - Transforms deeply nested Schemas into Swagger JSON Schema definitions - Extended & symmetric JSON & String serialization & coercion @@ -37,7 +37,7 @@ The Schema allows mostly any extra keys as ring-swagger tries not to be on your [API Docs](http://metosin.github.io/ring-swagger/doc/). -### Simplest possible example +### Simplest possible example for swagger 2.0 ```clojure (require '[ring.swagger.swagger2 :as rs]) @@ -51,8 +51,34 @@ The Schema allows mostly any extra keys as ring-swagger tries not to be on your ; :paths {}, ; :definitions {}} ``` +### Simplest possible example for openapi 3.0 -### More complete example +```clojure +(require '[ring.swagger.openapi3 :as rs]) +(rs/openapi-json {:info {:version "version" + :title "title" + :description "description" + :termsOfService "jeah" + :contact {:name "name" + :url "http://someurl.com" + :email "tommi@example.com"} + :license {:name "name" + :url "http://someurl.com"}} + :paths {}}) +;{:openapi "3.0.3" +; :info {:title "title" +; :version "version" +; :description "description" +; :termsOfService "jeah" +; :contact {:name "name" :url "http://someurl.com" :email "tommi@example.com"} +; :license {:name "name" :url "http://someurl.com"}} +; :paths {} +; :components {:schemas {} +; :securitySchemes {} +; :responses {} +; :requestBodies {}}} +``` +### More complete example for swagger 2.0 Info, tags, routes and anonymous nested schemas. @@ -130,6 +156,64 @@ Info, tags, routes and anonymous nested schemas. ; :additionalProperties false, ; :required (:street :city)}}} ``` +### More complete example for openapi 3.x +```clojure +(require '[schema.core :as s]) +(require '[ring.swagger.openapi3 :as rs]) + +(s/defschema User {:id s/Str, + :name s/Str + :address {:street s/Str + :city (s/enum :tre :hki)}}) + + +(rs/openapi-json {:info {:version "version" + :title "title" + :description "description" + :termsOfService "jeah" + :contact {:name "name" + :url "http://someurl.com" + :email "tommi@example.com"} + :license {:name "name" + :url "http://someurl.com"}} + :paths {"/api" + {:post + {:requestBody {:content {"application/json" User}} + :responses {200 {:description "ok" + :content {"application/json" {:schema User}}}}}}}}) +;{:openapi "3.0.3", +; :info {:title "title", +; :version "version", +; :description "description", +; :termsOfService "jeah", +; :contact {:name "name", :url "http://someurl.com", :email "tommi@example.com"}, +; :license {:name "name", :url "http://someurl.com"}}, +; :paths {"/api" {:post {:requestBody {:$ref "#/components/requestBodies/User"}, +; :responses {200 {:$ref "#/components/responses/Response7944"}}}}}, +; :components {:schemas {"Response7944" {:type "object", +; :properties {:schema {:$ref "#/components/schemas/User"}}, +; :additionalProperties false, +; :required [:schema]}, +; "Response7944SchemaAddress" {:type "object", +; :properties {:street {:type "string"}, +; :city {:type "string", :enum (:tre :hki)}}, +; :additionalProperties false, +; :required [:street :city]}, +; "User" {:type "object", +; :properties {:id {:type "string"}, +; :name {:type "string"}, +; :address {:$ref "#/components/schemas/UserAddress"}}, +; :additionalProperties false, +; :required [:id :name :address]}, +; "UserAddress" {:type "object", +; :properties {:street {:type "string"}, :city {:type "string", :enum (:tre :hki)}}, +; :additionalProperties false, +; :required [:street :city]}}, +; :securitySchemes {}, +; :responses {:Response7944 {:description "ok", +; :content {"application/json" {:schema {:$ref "#/components/schemas/Response7944"}}}}}, +; :requestBodies {:User {:content {"application/json" {:schema {:$ref "#/components/schemas/User"}}}}}}} +``` producing the following ui: diff --git a/src/ring/swagger/openapi3.clj b/src/ring/swagger/openapi3.clj index d50ec49..837165d 100644 --- a/src/ring/swagger/openapi3.clj +++ b/src/ring/swagger/openapi3.clj @@ -171,8 +171,8 @@ (update-in [:requestBodySchemas] conj {(keyword body-name) (:requestBody definition)}) (update-in [:requestBodyDefinitions method] conj (str "#/components/requestBodies/" body-name)))) acc) responses-acc (reduce-kv (fn [acc-res k v] - (let [response-path (get-response-ref v) - response-name (if response-path (last (.split response-path "/")) (gensym)) + (let [response-path ^String (get-response-ref v) + response-name ^String (if response-path (last (.split response-path "/")) (gensym)) response-path-val (keyword response-name)] (-> acc-res (update-in [:responses method k] conj response-path) From f930475bee3dbbe23a0c76b466cb4d0c9e9a7e8b Mon Sep 17 00:00:00 2001 From: Rajkumar Natarajan Date: Fri, 8 Aug 2025 13:13:06 -0700 Subject: [PATCH 2/2] Incorporate the review comments --- src/ring/swagger/openapi3.clj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ring/swagger/openapi3.clj b/src/ring/swagger/openapi3.clj index 837165d..be6096e 100644 --- a/src/ring/swagger/openapi3.clj +++ b/src/ring/swagger/openapi3.clj @@ -148,7 +148,7 @@ transformed) route)) -(defn get-response-ref [v] +(defn get-response-ref ^String [v] (some-> (-> v :content vals @@ -171,8 +171,8 @@ (update-in [:requestBodySchemas] conj {(keyword body-name) (:requestBody definition)}) (update-in [:requestBodyDefinitions method] conj (str "#/components/requestBodies/" body-name)))) acc) responses-acc (reduce-kv (fn [acc-res k v] - (let [response-path ^String (get-response-ref v) - response-name ^String (if response-path (last (.split response-path "/")) (gensym)) + (let [response-path (get-response-ref v) + response-name (if response-path (last (.split response-path "/")) (gensym)) response-path-val (keyword response-name)] (-> acc-res (update-in [:responses method k] conj response-path)