Tutorial

Create Swagger compatible custom Phoenix JSON generator

This post was updated 27 Mar

api swagger phoenix

Swagger is one of the most popular API documentation tools and is open source. 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 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 were 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.Json

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 do 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 :my_app, :phoenix_swagger,
swagger_files: %{
"priv/static/swagger.json" => [
router: MyAppWeb.Router, # phoenix routes will be converted to swagger paths
endpoint: MyAppWeb.Endpoint # (optional) endpoint config used to set host, port and https schemes.
]
}
config :phoenix_swagger, json_library: Jason # If you don't use Poison

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

scope "/api/swagger" do
forward "/", PhoenixSwagger.Plug.SwaggerUI, otp_app: :my_app, swagger_file: "swagger.json"
end
def swagger_info do
%{
info: %{
version: "1.0",
title: "My App"
}
}
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 won’t 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 it 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", MyAppWeb 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 a 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 endpoints, there is more documentation:

Related Tutorials

Published 30 Jul - 2020
Updated 27 Mar

Getting started with GraphQL and Absinthe in Phoenix

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..

NEW
Published 27 Mar

Adding Modals to Phoenix 1.8 with DaisyUI

In Phoenix 1.8, the built-in modal component was removed. Instead, Phoenix now encourages developers to use separate LiveView pages for new and edit..