Что такое Swagger

Swagger UI это небольшая коллекция скриптов для создания интерактивной документации для API веб-приложений с REST протоколом. Очень полезно, если вы пишете приложение которое должно взаимодействовать с внешней системой, а договориться друг с другом в текстовом формате мало. Интерактивность проявляется в том что из документации можно делать HTTP-запросы, а сама документация зависит от комментариев в вашем коде.

Визуализатор

Документация основывается на JSON-схеме. Есть пример кода статичной документации с четырьмя файлами. В общем же случае надо скачать .zip архив последней стабильной ветки Swagger-UI, либо делать чекаут мастера. Визуализатор написан на coffee script + backbone.js

Поскольку документация подразумевается динамической, то и генерироваться она должна из кода с аннотациями, а не переписываться каждый раз. В отличие от docblox и прочих документаций, эта расчитана именно на серверное взаимодействие с GET, POST, PUT и DELETE методами и сама позволяет эмулировать запросы.

swagger_screenshot

Схема

Описание всех доступных файлов поставляется в resources.json, который ссылается на остальные файлы за деталями..

{
  apiVersion: "0.2",
  swaggerVersion: "1.1",
  basePath: "http://petstore.swagger.wordnik.com/api",
  apis: [
    {
      path: "/pet.{format}",
      description: "Operations about pets"
    },
    {
      path: "/user.{format}",
      description: "Operations about user"
    }
  ]
}

Сам файл с детальным описанием повторяет то что в resources.json, только теперь со всем списком методов=операций и используемыми входными параметрами..

{
  apiVersion: "0.2",
  swaggerVersion: "1.1",
  basePath: "http://petstore.swagger.wordnik.com/api",
  resourcePath: "/pet.{format}",
apis:[
  {
    path:"/pet.{format}/{pet_name}",
    description:"Operations about pets",
    operations:[
      {
        httpMethod:"GET",
        nickname:"getPetByName",
        responseClass:"Pet",
        "parameters":[
            {
            "name":"pet_name",
            "description":"Any A-Za-z characters please",
            "required":"true",
            "allowMultiple":"false",
            "dataType":"string",
            "paramType":"path"
            }
        ],
        summary:"Find pet by its name"
        notes: "Only Pets which you have permission to see will be returned",
        errorResponses:[
            {
            "code":"400",
            "reason":"Invalid Name characters provided"
            },
            {
            "code":"404",
            "reason":"No pets were found"
            }
        ]
      }
    ]
  }
  ],
"produces":["application/json"],
"models":[]
}

Генератор

Стабильные генераторы написаны в основном для java (в т.ч. для Play! фреймворка), scala и node.js. Не густо. Для php есть три независимых библиотеки которые как-то позволяют генерировать JSON-схему для визуализации. Ключевое слово как-то.

Я выбрал первую.. устанавливается легко.

git clone [email protected]:zircote/swagger-php.git swagger
cd swagger
composer install

Первая проблема — при запуске генерации json’а на основе аннотаций вылезли баги — сначала что -e (exclude) флага нехватало, потом что require не работает. А работает он так, что инклудит подряд все файлы и начинает с них читать, поэтому если вы инклудите файл с помощью констант каких-то, то он тут же рухнет. Поэтому он должен проходится по чистым классам-контроллерам и на основе них всё дампить.

php swagger.phar -p ../my_api/ -o ../my_api/doc_json/ -e ../index.php -f

С этой коммандой, в папке doc_json появятся результаты.

Вторая проблема в том как эти результаты подключить к Swagger UI. Дело в том, что обычно json файлы можно генерировать и в корень API, но тогда с Апачем возникает проблема, что не работает mod_rewrite. Во всяком случае у меня. Ведь мне надо что-бы скажем /comment/findByName/ перезаписывалось в index.php.

Апач же настырно находит comment.json и пытается у файла найти подпапки и падает. Идиотизм конечно, но я ни с какими флагами -F не смог его образумить. Поэтому всё пускаю через index.php. Даже выдачу этих json файлов. Конечно, если у вас сам API называется comment.json то тут уже сложно что придумать.

Схема описанная выше генерируется из аннотаций — resource.php на основе комментария к классу..


/**
 *@Swaggerresource(
 *     basePath="http://org.local/v1",
 *     swaggerVersion="1.0",
 *     apiVersion="1"
 * )
 *@Swagger (
 *     path="/leadresponder",
 *     value="Gets collection of leadresponders",
 *     description="This is a long description of what it does"
 *     )
 *@SwaggerProduces (
 *     'application/json',
 *     'application/xml'
 *     )
 *
 * @category   Organic
 * @package    Organic_V1
 * @subpackage Controller
 */
class LeadResponder_RoutesController{}

А API на основе комментариев к методам..


    /**
     *
     * @PUT
     *@SwaggerPath /{leadresponder_id}
     *@SwaggerOperation(
     *     value="Updates the existing leadresponder designated by the {leadresponder_id}",
     *     responseClass="leadresonder_route",
     *     multiValueResponse=false,
     *     tags="MLR"
     * )
     *@SwaggerError(code=400,reason="Invalid ID Provided")
     *@SwaggerError(code=403,reason="User Not Authorized")
     *@SwaggerError(code=404,reason="Lead Responder Not Found")
     *@SwaggerParam(
     *     description="ID of the leadresponder being requested",
     *     required=true,
     *     allowMultiple=false,
     *     dataType="integer",
     *     name="leadresponder_id",
     *     paramType="path"
     * )
     *@SwaggerParam(
     *     description="leadresponder_route being updated",
     *     required=true,
     *     allowMultiple=false,
     *     dataType="leadresponder_route",
     *     name="leadresponder_route",
     *     paramType="body"
     * )
     * @responseTypeInternal Model_LeadResponder_Route
     */
    public function putAction(){}

Модели

Параметры на выходе (return) для каждого метода прописываются в поле responseClass. Это фактически ссылка на возвращаемый тип данных, который может быть примитивом — строкой, числом и тп, либо составным классом. Эти классы описываются в свою очередь в поле models.

Модели аналогично объявляются в swagger-php..


/**
 * @SwaggerModel(
 *     id="leadresonder_route",
 *     description="some long description of the model"
 * )
 *
 * @property integer $usr_mlr_route_id some long winded description.
 * @property string $route some long description of the model.
 * @property string $createdDate
 * @property array<ref:tag> $tags this is a reference to `tag`
 * @property array<string> $arrayItem This is an array of strings
 * @property array<integer> $refArr This is an array of integers.
 * @property string<'Two Pigs','Duck', 'And 1 Cow'> $enumVal This is an enum value.
 *
 */
class Model_LeadResponder_Route{}