Use Swagger to document a Symfony API
Tags: swagger, jane, behat, api
Published: 2017-12-16 18:38:13

---
title: Use Swagger to document a Symfony API
published: true
description: Use Swagger specification to document a Symfony API
tags: swagger, jane, behat, api
---

Web APIs are trending !

They are now everywhere : they fuel Javascript single-app pages with data, they allow developers to manage an elasticsearch instance, they are used to decouple monolithic applications into micro-services ...

And because they are widely used in modern web apps, we can see that the tooling for APIs has upgraded a lot too. Automated API documentation systems, API client SDKs, REST user-friendly clients ...

I wanted to share some cool tool combinations tricks I have learned this year.
This post will show you how you can combine some tools together in order to build, for a php API:
- an accurate HTML documentation using Swagger
- a PHP API Client SDK using Jane
- API tests using Behat

I split the post in 2 parts because it was quite long to read.

# The API

I use in this example a simple [Symfony](http://symfony.com/) REST API to handle a Movies database.
It has 3 endpoints:

- `GET /v1/movies` to fetch movies from the database, which accepts some parameters: dir (sorting direction, "asc" or "desc"), page (for pagination) and sort (to select which field to sort on)
- `POST /v1/movie` to register a new movie into the database
- `DELETE /v1/movie/{id}` to delete an existing movie from the database

The DELETE endpoint is a soft delete: the record is marked as deleted but is not truly deleted.

The API was built using Symfony 3.1, a mysql database handled with DoctrineORM and the library FOSRestBundle. Nothing unusual here, Symfony developers will recognize something very standard:

<img src="https://user-images.githubusercontent.com/3830050/33962320-7af63958-e051-11e7-9e2e-86dc6fc54518.png" height="50%">

You can have a look at the code [here](https://github.com/matks/ApiCycle/tree/master/apps/movies-api).

# Swagger

Here comes the fun. The API is built and tested, now I would like other developers to use it (for example to build a cool JS frontend).

These developers will ask me "where's the doc ?" because they cannot guess how the API works.

I don't want to write this documentation, because I am a developer so I love to automate everything (especially boring tasks) and also because I do not want to update it everytime I modify the API. That is why I want it to be generated from the code.

If I am able to generate the documentation from my code, whenever I modify the code the documentation will be updated too. No more out-of-date doc, no more mispelled parameters.

There is multiple ways to build an automated HTML API documentation. For Symfony apps, the official documentation redirects to [NelmioApiDocBundle](https://symfony.com/doc/master/bundles/NelmioApiDocBundle/index.html) which is easy to use and efficient. It parses some of your app config and asks you to annotate what cannot be guessed. It generates then a great HTML documentation such as this one:

<img src="https://symfony.com/doc/master/bundles/NelmioApiDocBundle/_images/webview.png">

I chose not to use it and instead to generate a Swagger file for my API. Swagger is, [among other things](https://swagger.io/), a standard API JSON specification format that defines how to describe an API in a JSON file. What's cool about it is that this format is supported by a lot of API tools, so having a Swagger file about your API allows you to use all of these tools easily.

For example,
- [SwaggerUI](https://swagger.io/swagger-ui/) allows developers to visualize and interact with your API based on your Swagger file
- [StopLight.io](http://stoplight.io/) can build a documentation portal from your Swagger file
- [Postman](https://www.getpostman.com/) can use Swagger files to generate requests bodies and templates to make it easy for you to consume an API

## Annotate the API

So I needed to produce a Swagger file which described my API. I first tried to use the [Swagger option](https://symfony.com/doc/master/bundles/NelmioApiDocBundle/swagger-support.html) of NelmioApiDocBundle which allows to dump the API description as a Swagger file. However the file produced was using Swagger v1.2 specification while the tools I would use later in this post required a Swagger v2 file.

There are tools such as [api-spec-converter](https://github.com/LucyBot-Inc/api-spec-converter) to convert a Swagger v1 file into a Swagger v2 file but I had a a lot of issues because of this conversion so I decided to go for a v2 file directly.

I used the [swagger-php](https://github.com/zircote/swagger-php) project to add annotations to my Symfony API which can then be parsed to produce the wanted file. Basically you need to annotate your Controllers and the Models being used (request bodies and response bodies).

For example here are the annotations needed to describe the GET endpoint:
```
    /**
     * @SWG\Get(
     *     path="/movies",
     *     summary="Get movies",
     *     description="Get movies",
     *     operationId="getMovies",
     *     produces={"application/json"},
     *     @SWG\Parameter(
     *         name="order",
     *         in="query",
     *         description="Order criterion",
     *         type="string",
     *     ),
     *     @SWG\Parameter(
     *         name="dir",
     *         in="query",
     *         description="Sort criterion",
     *         type="string",
     *     ),
     *     @SWG\Parameter(
     *         name="page",
     *         in="query",
     *         description="Page number",
     *         type="integer",
     *     ),
     *     @SWG\Response(
     *         response=200,
     *         description="Success",
     *         @SWG\Schema(ref="#/definitions/MoviesViewDTO"),
     *     )
     * )
     */
    public function getMoviesAction(Request $request)
```

The syntax is quite straight-forward, you have to describe what your endpoint accepts as parameters / request bodies and what it returns.

About the request and responses bodies, Swagger-php is able to analyze PHP models to extract their structure if provided with some annotations:

```
/**
 * @SWG\Definition()
 */
class MoviesViewDTO
{
    /**
     * @var int
     *
     * @SWG\Property()
     */
    public $total;
    ...
```

So if you accept and return DTOs (a.k.a POPOs), you can easily extract their structure to be written in the Swagger file.

Once you have annotated your routes and your models, you can run the swagger php binary on your project and it generates your Swagger file. It looks like this:

```
{
    "swagger": "2.0",
    "info": {
        "title": "Movies API",
        "version": "1.0"
    },
    "basePath": "/v1",
    "schemes": [
        "http"
    ],
    "paths": {
        "/movies": {
            "get": {
                "summary": "Get movies",
                "description": "Get movies",
                "operationId": "getMovies",
                "produces": [
                    "application/json"
                ],
                "parameters": [
                    {
                        "name": "order",
                        "in": "query",
                        "description": "Order criterion",
                        "type": "string"
                    },
                    {
                        "name": "dir",
                        "in": "query",
                        "description": "Sort criterion",
                        "type": "string"
                    },
                    ...
}
```

The complete file is available on [github](https://github.com/matks/ApiCycle/blob/master/apps/movies-api-client/swagger/swagger.json).

Congratulations: the Swagger file is written !

## Use the Swagger file

### HTML documentation

Now that we got this file we can use [swagger-editor](https://editor.swagger.io/) to see what the HTML documentation looks like. We just dump the JSON content into the editor and it renders the HTML doc:

<img src="https://user-images.githubusercontent.com/3830050/33962334-83b5a6b4-e051-11e7-9e66-b67ca921c692.png">

The doc can then be dumped and hosted on a webserver so it is available all the time for developers to look at it. And if you use SwaggerUI, you even are provided sandbox capabilities to perform real HTTP requests to see the API behave in realtime !

<img src="https://user-images.githubusercontent.com/3830050/33962346-8c0d8b92-e051-11e7-9370-e37bc8157d1b.png">

### Use it with a REST client

We can also input it in [Postman](https://www.getpostman.com/) to obtain a pre-configured REST client to interact with the API:

<img src="https://user-images.githubusercontent.com/3830050/33962356-95c8c692-e051-11e7-8764-7abf7d283aca.png">
<img src="https://user-images.githubusercontent.com/3830050/33962367-9bb55700-e051-11e7-8caa-a7407eb1b50c.png">

The requests are preconfigured and now it is very easy to perform HTTP requests from the client. This is especially useful when onboarding a new developer on the team, so he gets his dev/debug tool ready in a few seconds !

## Use it as a team collaboration tool

If your company have a backend team which works on an API and a frontend team which uses this API, they need to discuss and agree on the API behavior.

Using Swagger specification can be useful: when working on a new feature, the 2 teams work together on the Swagger file and agree that the updated file is what the API needs to be for the feature. Then the backend team starts working on the implementation of the Swagger specification, while the frontend team can start working because they know what the API will accept and return. Some tools can even generate mock APIs using a Swagger file in order to provide the frontend team a mock API to use until the backend team finishes its job.

## Jane & Behat

See you in the [2nd part](https://dev.to/mathieuks/use-swagger-jane-and-behat-to-document-and-test-a-symfony-api---part-2-d47) of this post :)