Psst. It would be super cool if you could try the new Phoenix Boilerplate!

Try now

Tutorial

View on Github

Create Swagger compatible custom Phoenix JSON generator

This post was updated 01 May

apiphoenixswagger

I’m in the process of creating an API in Phoenix and I want it to support Swagger documentation without me having to do much. I dont want to go in to every file and do this afterwards but I want all the needed code to be generated when I run my generator.

Swagger is one of the most popular API documentation tools and is open source. And they describe themselves as:

“Swagger UI allows anyone - be it your development team or your end consumers - to visualize and interact with the API’s resources without having any of the implementation logic in place.”

https://swagger.io/tools/swagger-ui/

The goal is to be able to type mix mix swagger.gen.json .. instead of mix phx.gen.json ..

STEP 1

A good place to start is to copy the actual generator from the files that was created when the project was generated.

mkdir -p lib/mix/tasks
cp deps/phoenix/lib/mix/tasks/phx.gen.json.ex lib/mix/tasks/swagger.gen.json.ex

Then open the file and rename the module to

Mix.Tasks.Swagger.Gen.Jason

And in the file, we also need to change all instances of phx to swagger

The commands to create the folder and copy the generator files over are:

mkdir -p priv/templates/swagger.gen.json
cp -a deps/phoenix/priv/templates/phx.gen.json/. priv/templates/swagger.gen.json

If you managed to to this without mistakes you should be able to run:

mix compile && mix help | grep 'swagger'

If everything works, you should see something like:

STEP 2

For this to work, you also need to have the Phoenix Swagger library installed. So, add that to the mix.exs

{:phoenix_swagger, "~> 0.8"},
{:ex_json_schema, "~> 0.5"}

And run:

mix deps.get

In the config file config/config.exs add the package configuration:

config :tutorial, :phoenix_swagger,
  swagger_files: %{
    "priv/static/swagger.json" => [
      router: TutorialWeb.Router,     # phoenix routes will be converted to swagger paths
      endpoint: TutorialWeb.Endpoint  # (optional) endpoint config used to set host, port and https schemes.
    ]
  }

config :phoenix_swagger, json_library: Jason # If you dont use Poison

You also need to add a route to Swagger UI and add a Swagger definition in the router. Open lib/tutorial_web/router.ex and add:

  scope "/api/swagger" do
    forward "/", PhoenixSwagger.Plug.SwaggerUI, otp_app: :tutorial, swagger_file: "swagger.json"
  end

  def swagger_info do
    %{
      info: %{
        version: "1.0",
        title: "Tutorial App - Fullstack Phoenix"
      }
    }
  end

Swagger works by reading a swagger.json file where all the API-information is documented. That file is auto generated with a generator that comes with the package.
Now you should be able to test this by running:

mix phx.swagger.generate

And see something like:

STEP 3

All that is left to change is to modify the controller template. priv/templates/swagger.gen.json/controller.ex

I wont post all code in here but I will link to the changes in Github.

But there are basically 3 types of changes.

  1. Add the use PhoenixSwagger in the top of the file
  2. Add a swagger_path :index do for every type of action
  3. In the bottom, add a def swagger_definitions do function.

When is run, we will end up with code that looks like this for the index function:

  swagger_path :index do
    get "/api/users"
    summary "List users"
    description "List all users in the database"
    tag "Users"
    produces "application/json"
    response(200, "OK", Schema.ref(:UsersResponse),
      example: %{
        data: [
          %{
            id: 1,
            count: 42,
            email: "some email",
            name: "some name",
            private: true,
            profile: "some profile",
          }
        ]
      }
    )
  end

  def index(conn, _params) do
    users = Users.list_users()
    render(conn, "index.json", users: users)
  end

And similar code for all other generated functions.

STEP 4

Next step is to test this out. I want to generate an API endpoint for users so I run:

mix swagger.gen.json Users User users name email profile:text private:boolean count:integer

I should get the normal output and the message that I need to add the users routes.

  scope "/api", TutorialWeb do
    pipe_through :api
    resources "/users", UserController, except: [:new, :edit]
  end

Then I can run:

mix ecto.migrate

And after that I can rerun the command to update my swagger documentation. I need to do this since I have generated to controller that tells swagger about my new endpoints.

mix phx.swagger.generate

Start the server and navigate to http://localhost:4000/api/swagger

You should now see:

And if you click on one of the endpoint, there is more documentation:


What are you working on?

If you want, you can send me a link to your Phoenix or Phoenix LiveView project so. Lets connect on Twitter or Linkedin.

- Andreas Eriksson, web developer since 2005

Related Tutorials

Published 22 Jul

Combining authentication solutions with Guardian and Phx Gen Auth

authenticationguardianapi

Many web apps have both a web interface and an Json api. When the normal web app has a classic session based authentication, an API need something l..

Published 30 Jul

Getting started with GraphQL and Absinthe in Phoenix

phoenixgraphqlapiabsinthe

In the last tutorial, there I had an app with a simple rest api that was authenticated with Guardian and Json Web Token. In this tutorial, I will go..