402 lines
9.6 KiB
Markdown
402 lines
9.6 KiB
Markdown
# Getting started
|
|
|
|
## Installation
|
|
|
|
We recommend adding swagger-php to your project with [Composer](https://getcomposer.org)
|
|
|
|
```bash
|
|
composer require zircote/swagger-php
|
|
```
|
|
|
|
## Usage
|
|
|
|
Generate always-up-to-date documentation.
|
|
|
|
```php
|
|
<?php
|
|
require("vendor/autoload.php");
|
|
|
|
$openapi = \OpenApi\Generator::scan(['/path/to/project']);
|
|
|
|
header('Content-Type: application/x-yaml');
|
|
echo $openapi->toYaml();
|
|
```
|
|
|
|
This will scan the php-files in the given folder(s), look for OpenApi annotations and output a json file.
|
|
|
|
Complete documentation of how to use the `Generator` class can be found in the [Generator Migration](https://zircote.github.io/swagger-php/Generator-migration.html) guide.
|
|
|
|
## CLI
|
|
|
|
Instead of generating the documentation dynamically we also provide a command line interface.
|
|
This allows to write the documentation to a static yaml/json file.
|
|
|
|
```bash
|
|
./vendor/bin/openapi --help
|
|
```
|
|
|
|
For cli usage from anywhere install swagger-php globally and add the `~/.composer/vendor/bin` directory to the PATH in your environment.
|
|
|
|
```bash
|
|
composer global require zircote/swagger-php
|
|
```
|
|
|
|
## Write annotations
|
|
|
|
The goal of swagger-php is to generate a openapi.json using phpdoc annotations.
|
|
|
|
#### When you write:
|
|
|
|
```php
|
|
/**
|
|
* @OA\Info(title="My First API", version="0.1")
|
|
*/
|
|
|
|
/**
|
|
* @OA\Get(
|
|
* path="/api/resource.json",
|
|
* @OA\Response(response="200", description="An example resource")
|
|
* )
|
|
*/
|
|
```
|
|
|
|
#### swagger-php will generate:
|
|
|
|
```yaml
|
|
openapi: 3.0.0
|
|
info:
|
|
title: "My First API"
|
|
version: "0.1"
|
|
paths:
|
|
/api/resource.json:
|
|
get:
|
|
responses:
|
|
"200":
|
|
description: "An example resource"
|
|
```
|
|
|
|
### Using variables
|
|
|
|
You can use constants inside doctrine annotations.
|
|
|
|
```php
|
|
define("API_HOST", ($env === "production") ? "example.com" : "localhost");
|
|
```
|
|
|
|
```php
|
|
/**
|
|
* @OA\Server(url=API_HOST)
|
|
*/
|
|
```
|
|
|
|
When you're using the CLI you'll need to include the php file with the constants using the `--bootstrap` options:
|
|
|
|
```bash
|
|
openapi --bootstrap constants.php
|
|
```
|
|
|
|
### Annotation placement
|
|
|
|
You shouldn't place all annotations inside one big @OA\OpenApi() annotation block, but scatter them throughout your codebase.
|
|
swagger-php will scan your project and merge all annotations into one @OA\OpenApi annotation.
|
|
|
|
The big benefit swagger-php provides is that the documentation lives close to the code implementing the API.
|
|
|
|
### Arrays and Objects
|
|
|
|
Doctrine annotation supports arrays, but uses `{` and `}` instead of `[` and `]`.
|
|
|
|
Doctrine also supports objects, which also use `{` and `}` and require the property names to be surrounded with `"`.
|
|
|
|
::: warning DON'T WRITE
|
|
|
|
```php
|
|
/**
|
|
* @OA\Info(
|
|
* title="My first API",
|
|
* version="1.0.0",
|
|
* contact={
|
|
* "email": "support@example.com"
|
|
* }
|
|
* )
|
|
*/
|
|
```
|
|
|
|
:::
|
|
|
|
This "works" but most objects have an annotation with the same name as the property, such as `@OA\Contact` for `contact`:
|
|
|
|
::: tip WRITE
|
|
|
|
```php
|
|
/**
|
|
* @OA\Info(
|
|
* title="My first API",
|
|
* version="1.0.0",
|
|
* @OA\Contact(
|
|
* email="support@example.com"
|
|
* )
|
|
* )
|
|
*/
|
|
```
|
|
|
|
:::
|
|
|
|
This also adds validation, so when you misspell a property or forget a required property, it will trigger a PHP warning.
|
|
For example, if you write `emial="support@example.com"`, swagger-php would generate a notice with `Unexpected field "emial" for @OA\Contact(), expecting "name", "email", ...`
|
|
|
|
Placing multiple annotations of the same type will result in an array of objects.
|
|
For objects, the key is defined by the field with the same name as the annotation: `response` in a `@OA\Response`, `property` in a `@OA\Property`, etc.
|
|
|
|
```php
|
|
/**
|
|
* @OA\Get(
|
|
* path="/products",
|
|
* summary="list products",
|
|
* @OA\Response(
|
|
* response=200,
|
|
* description="A list with products"
|
|
* ),
|
|
* @OA\Response(
|
|
* response="default",
|
|
* description="an ""unexpected"" error"
|
|
* )
|
|
* )
|
|
*/
|
|
```
|
|
|
|
#### Results in:
|
|
|
|
```yaml
|
|
openapi: 3.0.0
|
|
paths:
|
|
/products:
|
|
get:
|
|
summary: "list products"
|
|
responses:
|
|
"200":
|
|
description: "A list with products"
|
|
default:
|
|
description: 'an "unexpected" error'
|
|
```
|
|
|
|
### Detects values based on context
|
|
|
|
swagger-php looks at the context of the comment which reduces duplication.
|
|
|
|
```php
|
|
/**
|
|
* @OA\Schema()
|
|
*/
|
|
class Product {
|
|
|
|
/**
|
|
* The product name
|
|
* @var string
|
|
* @OA\Property()
|
|
*/
|
|
public $name;
|
|
}
|
|
```
|
|
|
|
#### Results in:
|
|
|
|
```yaml
|
|
openapi: 3.0.0
|
|
components:
|
|
schemas:
|
|
Product:
|
|
properties:
|
|
name:
|
|
description: "The product name"
|
|
type: string
|
|
type: object
|
|
```
|
|
|
|
#### As if you'd written:
|
|
|
|
```php
|
|
/**
|
|
* The product name
|
|
* @var string
|
|
*
|
|
* @OA\Property(
|
|
* property="name",
|
|
* type="string",
|
|
* description="The product name"
|
|
* )
|
|
*/
|
|
public $name;
|
|
```
|
|
|
|
### Shortcuts
|
|
|
|
#### Anotation namespace
|
|
|
|
Instead of writing the <abbr title="Full Qualified Class Name">FQCN</abbr>: `@OpenApi\Annotations\Response()` you can write the shorter `@OA\Response()` instead.
|
|
|
|
This works because doctrine picks up on the use statements like:
|
|
|
|
```php
|
|
use OpenApi\Annotations as OA;
|
|
```
|
|
|
|
And swagger-php injects this namespace alias, even when it's not in the php file.
|
|
But if your editor supports doctrine annotation completion, you still need to add the namespace alias otherwise it can't find the annotation classes for autocompletion.
|
|
|
|
#### Json or Xml
|
|
|
|
The `@OA\MediaType` is used to describe the content:
|
|
|
|
```php
|
|
/**
|
|
* @OA\Response(
|
|
* response=200,
|
|
* description="successful operation",
|
|
* @OA\MediaType(
|
|
* mediaType="application/json",
|
|
* @OA\Schema(ref="#/components/schemas/User"),
|
|
* )
|
|
* ),
|
|
*/
|
|
```
|
|
|
|
But because most API requests and responses are JSON, the `@OA\JsonContent` allows you to write:
|
|
|
|
```php
|
|
/**
|
|
* @OA\Response(
|
|
* response=200,
|
|
* description="successful operation",
|
|
* @OA\JsonContent(ref="#/components/schemas/User"),
|
|
* )
|
|
*/
|
|
```
|
|
|
|
During processing the `@OA\JsonContent` unfolds to `@OA\MediaType( mediaType="application/json", @OA\Schema(`
|
|
and will generate the same output.
|
|
|
|
On a similar note, you generally don't have to write a `@OA\PathItem` because this annotation will be generated based on the path in operation `@OA\Get`, `@OA\Post`, etc.
|
|
|
|
## Reusing annotations (ref)
|
|
|
|
It's common that multiple requests have some overlap in either the request or the response.
|
|
To keep things DRY (Don't Repeat Yourself) the specification includes referencing other parts of the JSON using `$ref`s
|
|
|
|
```php
|
|
/**
|
|
* @OA\Schema(
|
|
* schema="product_id",
|
|
* type="integer",
|
|
* format="int64",
|
|
* description="The unique identifier of a product in our catalog"
|
|
* )
|
|
*/
|
|
```
|
|
|
|
#### Results in:
|
|
|
|
```yaml
|
|
openapi: 3.0.0
|
|
components:
|
|
schemas:
|
|
product_id:
|
|
description: "The unique identifier of a product in our catalog"
|
|
type: integer
|
|
format: int64
|
|
```
|
|
|
|
This doesn't do anything by itself, but now you can reference this piece by its path in the JSON `#/components/schemas/product_id`
|
|
|
|
```php
|
|
/**
|
|
* @OA\Property(ref="#/components/schemas/product_id")
|
|
*/
|
|
public $id;
|
|
```
|
|
|
|
For more tips on refs, browse through the [using-refs example](https://github.com/zircote/swagger-php/tree/master/Examples/using-refs).
|
|
|
|
## Composition
|
|
|
|
You can combine model definitions into new schema compositions with [allOf](https://swagger.io/specification/#schemaComposition)
|
|
|
|
```php
|
|
/**
|
|
* @OA\Schema(
|
|
* schema="UpdateItem",
|
|
* allOf={
|
|
* @OA\Schema(ref="#/components/schemas/NewItem"),
|
|
* @OA\Schema(
|
|
* @OA\Property(property="id", type="integer"),
|
|
* @OA\Property(property="created_at", ref="#/components/schemas/BaseModel/properties/createdAt")
|
|
* )
|
|
* }
|
|
* )
|
|
*/
|
|
```
|
|
|
|
More info in the [Inheritance and Polymorphism](https://swagger.io/docs/specification/data-models/inheritance-and-polymorphism/) chapter.
|
|
|
|
## Array parameters in query
|
|
|
|
Depending on [style-values](https://swagger.io/specification/#style-values) `@OA\Parameter(in="query", name="param", ...)` might create urls like this: `path?param=123¶m=abc` which doesn't work when reading the param values in php.
|
|
|
|
The solution is to change the name `param` into `param[]` which will create
|
|
`path?param[]=123¶m[]=abc` and results in an php array.
|
|
|
|
## Vendor extensions
|
|
|
|
The specification allows for [custom properties](http://swagger.io/specification/#vendorExtensions) as long as they start with "x-". Therefore all swagger-php annotations have an `x` property which will unfold into "x-" properties.
|
|
|
|
```php
|
|
/**
|
|
* @OA\Info(
|
|
* title="Example",
|
|
* version="1.0.0",
|
|
* x={
|
|
* "some-name": "a-value",
|
|
* "another": 2,
|
|
* "complex-type": {
|
|
* "supported":{
|
|
* {"version": "1.0", "level": "baseapi"},
|
|
* {"version": "2.1", "level": "fullapi"},
|
|
* }
|
|
* }
|
|
* }
|
|
* )
|
|
*/
|
|
```
|
|
|
|
#### Results in:
|
|
|
|
```yaml
|
|
openapi: 3.0.0
|
|
info:
|
|
title: Example
|
|
version: 1
|
|
x-some-name: a-value
|
|
x-another: 2
|
|
x-complex-type:
|
|
supported:
|
|
- version: "1.0"
|
|
level: baseapi
|
|
- version: "2.1"
|
|
level: fullapi
|
|
```
|
|
|
|
The [Amazon API Gateway](http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions.html) for example, makes use of these.
|
|
|
|
## OpenApi
|
|
|
|
To learn about what you can generate, which options to use and how, look at the [docs on swagger.io](https://swagger.io/docs/)
|
|
|
|
It has sections about:
|
|
|
|
- [Basic structure](https://swagger.io/docs/specification/basic-structure/)
|
|
- [Describing parameters](https://swagger.io/docs/specification/describing-parameters/)
|
|
- [Describing responses](https://swagger.io/docs/specification/describing-responses/)
|
|
- and [more](https://swagger.io/docs/specification/about/)
|
|
|
|
For more detailed information look at the [OpenApi Specification](http://swagger.io/specification/)
|