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

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:


Related Tutorials

Published 11 Jun

Introducing Boilerplate Builder

phoenixboilerplate

I have started a new project. Its a free PhoenixBoilerplate that you tweak and select features after your need and taste. The background is that I ..

Published 30 Jun

Nested Templates and Layouts in Phoenix Framework

templateslayoutsphoenix

Eventually when your site reach a certain maturity, you look into ways to refactor the code. One is to add parts of the templates in reusable layout..