Giter Club home page Giter Club logo

pedestal-swagger's Introduction

pedestal-swagger

Build status Dependencies Status

Generate Swagger documentation from pedestal routes

Download

Clojars Project

Usage

(:require [io.pedestal.interceptor.helpers :as interceptor]
          [schema.core :as schema]
          [pedestal.swagger.core :as swagger]
          [pedestal.swagger.doc :as swagger.doc])

Annotate your interceptors using swagger.doc/annotate. This function will attach swagger metadata to your interceptor.

(def my-endpoint
  (swagger/annotate
   {:summary "Endpoint for stuff"
    :description "This is an interesting endpoint"
    :parameters {:query {:param1 schema/Bool}
                 :body {:param2 schema/Str
                        :param3 schema/Inst}}
    :responses {:default {:headers {:x-tracking schema/Uuid}}
                418 {:description "I'm sorry, I'm a teapot"}}}
   (interceptor/handler
    ::my-endpoint
    (fn [request]
      ...))))

You can use these interceptors just like any other interceptors in your route definition.

(defroutes routes [[["/my-endpoint" {:get my-endpoint}]]])

And of course there are some helping macros in the swagger namespace to help you define them more succintely.

(swagger/defhandler my-handler
  {:summary ".."
   :parameters {..}
   :responses {..}}
  [request]
  ...)

A swagger path specification can be generated from your route table. You can inspect at any time what it looks like calling gen-paths.

(swagger.doc/gen-paths routes)

;; => {"/my-endpoint" {:get {...}} ...}

But what you normally want is to inject the swagger paths in your route table, so that is available to your interceptors. There's a handy macro for that.

(swagger/defroutes routes
  {:info {:title "Swagger API"
          :description "Swagger + Pedestal api"}}
  [[["/my-endpoint" {:get my-endpoint}]]])

The second argument to defroutes is an optional map that will be merged with the generated paths and some default values to create a complete swagger documentation. The resulting swagger object looks like this:

{:swagger "2.0"
 :info {:title "Swagger API"
        :description "Swagger + Pedestal api"
        :version "0.0.1"}
 :paths {"/my-endpoint" {...}}}

A special handler can be added to convert this data structure in a json schema and serve it on a path (usually named swagger.json):

(swagger/defroutes routes
  [[["/my-endpoint" {:get my-endpoint}]
    ["/swagger.json" {:get [(swagger/swagger-json)]}]]])

And of course you can add a swagger-ui endpoint to provide an easy way to view and play with your API.

(swagger/defroutes routes
  [[["/my-endpoint" {:get my-endpoint}]
  ["/swagger/swagger.json" {:get [(swagger/swagger-json)]}]
  ["/swagger/*resource" {:get [(swagger/swagger-ui)]}]]])

Note that the swagger-ui endpoint requires a *resource splat parameter.

If your endpoint is a plain ring handler or a pedestal interceptor it will not be included in your documentation.

(defn a-hidden-endpoint [request]
 ...)

All this would be a little uninteresting if we weren't able to leverage one of Pedestal's most interesting features: sharing logic between endpoints via interceptors.

A common pattern is to have an interceptor at the root of a path that loads a resource.

(swagger/defon-request load-thing-from-db
  {:parameters {:path {:id schema/Int}}
   :responses {404 {:description "Couldn't find the thing in the db"}}}
   [request]
    ...)

(swagger/defroutes routes
  [[["/thing/:id" ^:interceptors [load-thing-from-db]
      {:get do-get-thing}
      {:put do-update-thing}
      {:delete do-delete-thing}]]])

All the documentation specified in the interceptor (such as parameters, responses, description) will be inherited by the endpoints on the same path. Thus you can reuse both behaviour and the documentation for said behaviour.

And finally we want to be able to use the schemas in the documentation to check the incoming parameters or the outgoing responses. To do so we can include swagger/coerce-request and swagger/validate-response at the top of our route spec. The default behaviour of these interceptors could be overridden passing a custom coercion or validation function.

(swagger/defroutes routes
  [[["/" ^:interceptors [(swagger/serialise-response)
                         (swagger/body-params)
                         (swagger/coerce-request)
                         (swagger/validate-response)]
     ["/thing/:id" ^:interceptors [load-thing-from-db]
      {:get do-get-thing}
      {:put do-update-thing}
      {:delete do-delete-thing}]]]])

Note that you usually need to include (swagger/body-params) as it will make sure the keys in the request map are where the validator expects to find them. Each interceptor can still be configured to tweak its default behaviour.

An interceptor with sensible error handling for most of swagger use cases is available under pedestal.swagger.error namespace, but you're encouraged to build your own using pedestal pattern matching.

The swagger/serialise-response interceptor provides content-negotiation for the serialisers built in to Pedestal. You can extend it with your own content-types by passing in a map similar to pedestal.swagger.content-negotiation/default-serialisation-interceptors.

For a complete example have a look at the sample project.

Roadmap

  • Support multiple swagger.json and swagger-ui endpoints (e.g. for versioned apis)
  • Documenting consumes
  • More failures at compile time (tags not in sync, produces/consumes not in sync)

License

Copyright © 2014 Frankie Sardo

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

pedestal-swagger's People

Contributors

frankiesardo avatar aew avatar oliyh avatar stuarth avatar ikitommi avatar eunmin avatar jplaza avatar kpuputti avatar dalzony avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.