Code Monkey home page Code Monkey logo

cowboy_swagger's Introduction

cowboy-swagger

Swagger integration for Cowboy (built on trails).

build

Contact Us

If you find any bugs or have a problem while using this library, please open an issue in this repo (or a pull request :)).

Why Cowboy Swagger?

Simple, because there isn't a tool in Erlang to document Cowboy RESTful APIs easy and fast, and to improve development productivity.

With cowboy_swagger is possible to integrate Swagger to your Erlang projects that use Cowboy as a web server. It is extremely easy to use, and with just a few steps you'll have a nice Web documentation for your RESTful APIs.

To learn a bit more about Swagger, please check this blog post.

How to Use it?

This is the best part. It is extremely easy.

1. Document each Cowboy Handler

Because cowboy_swagger runs on top of trails, the first thing that you have to do is document all about your handler within the trails metadata. Keep in mind that all fields defined within each method into the metadata must be compliant with the Swagger specification.

For example, suppose that you have example_echo_handler, so it must implement the c:trails_handler:trails/0 callback:

trails() ->
  Metadata =
    #{get =>
      #{tags => ["echo"],
        description => "Gets echo var from the server",
        produces => ["text/plain"]
      },
      put =>
      #{tags => ["echo"],
        description => "Sets echo var in the server",
        produces => ["text/plain"],
        parameters => [
          #{name => <<"echo">>,
            description => <<"Echo message">>,
            in => <<"path">>,
            required => false,
            type => <<"string">>}
        ]
      }
    },
  [trails:trail("/message/[:echo]", example_echo_handler, [], Metadata)].

To get a better idea of how your handler should look like, please check example/src/example_echo_handler.erl.

2. Include cowboy_swagger in your app

First, you need to include cowboy_swagger_handler module in your list of trails to be compiled.

% Include cowboy_swagger_handler in the trails list
Trails = trails:trails([example_echo_handler,
                        example_description_handler,
                        cowboy_swagger_handler]),
% store them
trails:store(Trails),
% and then compile them
Dispatch = trails:single_host_compile(Trails),

The snippet of code above is usually placed when you start cowboy. Check it here.

Then add cowboy_swagger to the list of apps to be loaded in your *.app.src file.

{application, example,
 [
  {description, "Cowboy Swagger Basic Example."},
  {vsn, "0.1"},
  {applications,
   [kernel,
    stdlib,
    jsx,
    cowboy,
    trails,
    cowboy_swagger
   ]},
  {modules, []},
  {mod, {example, []}},
  {registered, []},
  {start_phases, [{start_trails_http, []}]}
 ]
}.

And that's it, you got it. Now start your application and then you will have access to the API docs under the path /api-docs. Supposing that you're running the app on localhost:8080, that will be http://localhost:8080/api-docs.

Configuration

Additionally, cowboy_swagger can be configured/customized from a *.config file:

app.config

[
 %% Other apps ...

 %% cowboy_swagger config
 {cowboy_swagger,
  [
   %% `static_files`: Static content directory. This is where Swagger-UI
   %% is located. Default: `priv/swagger`.
   %% Remember that Swagger-UI is embedded into `cowboy-swagger` project,
   %% within `priv/swagger` folder. BUT you have to reference that path,
   %% and depending on how you're using `cowboy-swagger` it will be different.
   %% For example, assuming that you want to run your app which has
   %% `cowboy-swagger` as dependency from the console, `static_files` will be:
   {static_files, "./deps/cowboy_swagger/priv/swagger"},

   %% `global_spec`: Global fields for Swagger specification.
   %% If these fields are not set, `cowboy_swagger` will set default values.
   {global_spec,
    #{swagger => "2.0",
      info => #{title => "Example API"},
      basePath => "/api-docs"
     }
   }
  ]
 }
].

Definitions

Definitions can be used for describing parameters, responses and security schemas.

For adding definitions to your app, you have 2 choices:

  1. Add a definitions key to your cowboy_swagger global_spec map.
  2. Add them by calling cowboy_swagger:add_definition/2 and send the definition's name and properties.

Let's say you want to describe a POST call to a newspapers endpoint that requires name and description fields only, you can do it like this:

Option 1:

[ ... % other configurations
, { cowboy_swagger
  , [ { global_spec
      , #{ swagger => "2.0"
         , info => #{title => "My app API"}
         , definitions => #{
             "RequestBody" =>
               #{ "name" =>
                   #{ "type" => "string"
                    , "description" => "Newspaper name"
                    }
                , "description" =>
                    #{ "type" => "string"
                     , "description" => "Newspaper description"
                     }
                }
           }
         }
      }
    ]
  }
]

Option 2:

For the second choice, you can do it for example in one or several start_phases, directly in your handler or any other place you want.

-spec trails() -> trails:trails().
trails() ->
  DefinitionName = <<"RequestBody">>,
  DefinitionProperties =
    #{ <<"name">> =>
         #{ type => <<"string">>
          , description => <<"Newspaper name">>
          }
     , <<"description">> =>
         #{ type => <<"string">>
          , description => <<"Newspaper description">>
          }
     },
  % Add the definition
  ok = cowboy_swagger:add_definition(DefinitionName, DefinitionProperties),
  ...

Now in your handler's trails callback function you can use it:

...
  RequestBody =
    #{ name => <<"request body">>
     , in => body
     , description => <<"request body (as json)">>
     , required => true
       % Use the previously created `RequestBody' definition
     , schema => cowboy_swagger:schema(<<"RequestBody">>)
     },
  Metadata =
    #{ get =>
       #{ tags => ["newspapers"]
        , description => "Returns the list of newspapers"
        , produces => ["application/json"]
        }
     , post =>
       # { tags => ["newspapers"]
         , description => "Creates a new newspaper"
         , consumes => ["application/json"]
         , produces => ["application/json"]
         , parameters => [RequestBody] % and then use that parameter here
         }
     },
  Path = "/newspapers",
  Options = #{path => Path},
  [trails:trail(Path, newspapers_handler, Options, Metadata)].

What this does for you is add a nice response, parameter or security model in swagger-ui, so client developers will know exactly what parameters the API expects for every endpoint.

Example

For more information about cowboy_swagger and how to use it, please check this Example.

cowboy_swagger's People

Contributors

amilkr avatar bernardnotarianni avatar brucify avatar cabol avatar dddhuang avatar egobrain avatar elbrujohalcon avatar erszcz avatar euen avatar ferigis avatar freke avatar harenson avatar hernanrivasacosta avatar igaray avatar jfacorro avatar joaohf avatar paulo-ferraz-oliveira avatar richcarl avatar szlartibartfaszt79 avatar teebeelol avatar zhongwencool avatar zmstone avatar zsoci avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cowboy_swagger's Issues

Swagger compliance

I ran some compliance issues which can be fixed in the examples section (how to use cowboy-swagger), or in the code itself (what cowboy-swagger generates).

  • in the info object version of the api is required (there should be some generated version in default)
  • swagger editor [1] also complained about the missing basePath. Even when I specified basePath in the app.config I didn't see in the json, probably it didn't pick up the value.
  • a path parameter needs a type field (it seems to be required), it can be string or number see spec [2]. format which is optional but in numeric cases would be good to see an example.
  • when responses are needed, it needs at least:
"responses": {
    "default": {
        "description": ""
    }
}

but one can specify schema per http response code. See links below [2].

  • For body parameters I needed to define a "schema": {} at least, in order that the JSON would be compliant. required is not required here, type is forbidden.

I didn't have time to discover all parts of schema, but it would be a good example how to define request bodies which conform to a json.

[1] http://editor.swagger.io/#/
[2] http://swagger.io/specification/

Wrong inaka_mixer dependency

My rebar.config is:

{deps, [
      {cowboy_swagger, "0.1.1"}
]}.
``

joaohf@porco:~/p/x$ make
===> Verifying dependencies...
===> Package inaka_mixer-0.1.4 not found. Fetching registry updates and trying again...
===> Updating package registry...
===> Writing registry to /home/joaohf/.cache/rebar3/hex/default/registry
===> Generating package index...
===> Writing index to /home/joaohf/.cache/rebar3/hex/default/packages.idx
===> Package not found in registry: inaka_mixer-0.1.4.
Makefile:10: recipe for target 'compile' failed
make: *** [compile] Error 1


$ rebar3 hex search swagger
cowboy_swagger: 0.1.1
$ rebar3 hex search mixer
inaka_mixer: 0.1.5

remove Makefile from the example

since it seems to be migrated to rebar3, also update the README, if you follow the current steps it doesn't work (make can't be called)

Hello can this project support the cowboy REST part?

According what I learned, the cowboy REST are not directly define the HTTP method such as "PUT", "GET", "POST", It uses the methods such as allowed_methods. I just wander that this app can supports the cowboy REST.
Thanks a lot.

Fix validate_metadata spec

It currently is

-spec validate_metadata(trails:metadata()) -> trails:metadata().

It should be

-spec validate_metadata(trails:metadata(_)) -> metadata().

Update documentation

Update documentation to inform that Erlang 18+ is required for the release 0.1.0

swagger UI always sends JSON

Regardless of what I add to the trails metadata for my endpoints, swagger always try to send contents as application/json:
swagger_ui

basePath should be considered part of the trails path

Even when #22 is fixed by just setting basePath => "", sometimes having a basePath (e.g. /admin/api) is actually useful, but swagger has to consider that such a basePath will be included in the trails routes, at least until inaka/cowboy-trails#22 is implemented. And in that case, basePath should be taken from there and not as an extra swagger property.

Definitions description in README

Hi !

When I followed instructions in README about creating schema then my swagger ui didn't work. It worked when I changed maps keys and values to binary string. So only the following configuration worked for me:

option 1:

`[ ... % other configurations
, { cowboy_swagger
  , [ { global_spec
      , #{ swagger => "2.0"
         , info => #{title => "My app API"}
         , definitions => #{
             <<"RequestBody">> =>
               #{ <<"name">> =>
                   #{ <<"type" => <<"string">>
                    , <<"description">> => <<"Newspaper name">>
                    }
                , <<"description">> =>
                        #{ <<"type" =><< "string">>
                     , <<"description">> => <<"Newspaper description">>
                    }
                }
           }
         }
      }
    ]
  }
]`

option2:

`-spec trails() -> trails:trails().
trails() ->
  DefinitionName = <<"RequestBody">>,
  DefinitionProperties =
    #{ <<"name">> =>
         #{ <<"type">> => <<"string">>
          , <<"description">> => <<"Newspaper name">>
          }
     , <<"description">> =>
         #{ <<"type">> => <<"string">>
          , <<"description">> => <<"Newspaper description">>
          }
     },
  % Add the definition
  ok = cowboy_swagger:add_definition(DefinitionName, DefinitionProperties),
  ...`

Is it a bug in README or maybe something has changed and broke the configuration?

Verify that for each path each cowboy binding has a correspondingly named parameter

E.g. a cowboy binding :id must have a corresponding Swagger parameter named id.

Current behaviour is that such constraint is not enforced hence cowboy_swagger generates /api-docs/swagger.json for UI accessible at /api-docs with path that may contain bindings with no corresponding parameter, hence causing curly variable template to be sent to server.


Example: trail with cowboy binding called :id and swagger parameter named key causes this Swagger UI...

swaggeruiwithkeyratherthanid

... that when clicking Try it out! sends to server something like /places/{id} - i.e. with no replaced value:

2017-03-09 13:15:16.503 [info] <0.942.0> PUT /places/%7Bid%7D

Fulfil the open-source check-list

Introduction

This is the list of things to check for every open-source project that we create

Usage

Each project should have a github repo with github issues enabled. As the main dev in that project, you should make sure to have the corresponding items from the lists below reported as issues there and work on having them implemented/done before releasing the 1.0 version of your product.

General Items

  • It has a github repo
  • It has a proper Apache2 LICENSE file
    • with the proper copyright: 2015 Erlang Solutions Ltd.
  • It's has a clear and useful README.md
  • It's documented (with examples)
  • It's tested
  • It's hooked to a the open-source hipchat room
  • It has a link to the open-source hipchat room in its README
  • It has a link to inaka.github.io in its README and/or landing page

Exhibition

  • There is a blog post about it
  • It's shared on social networks
  • It's shared on reddit
  • It's shared on hacker news with a title like Show HN: description
  • It has a landing page built in github pages

For Libraries

  • It provides a sample application
  • Examples of use are documented in the README or linked from there

For Erlang Projects

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.