Tutorial
Create Swagger compatible custom Phoenix JSON generator
This post was updated 01 May - 2020
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.
- Add the
use PhoenixSwagger
in the top of the file - Add a
swagger_path :index do
for every type of action - 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: