Matt Trask
@matthewtrask
PDX PHP - 04/20/2021
Matt Trask
@matthewtrask
Senior Product Architect
Primitive - @lead_primitive
Podcast Host
APIs You Wont Hate & PHP Townhall
OSS Maintainer
openapi.tools | phptherightway.com | other things
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
November 15th, 2006
Swagger -> OpenAPI
(under the Linux Foundation)
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
OpenAPI is a standard way to describe HTTP-based APIs through a series of collections in a JSON/YAML form.
Matt Trask
@matthewtrask
Terms to note
Matt Trask
@matthewtrask
New APIs or existing ones?
Matt Trask
@matthewtrask
New APIs or existing ones?
Yes!
Matt Trask
@matthewtrask
What is different between this and Swagger?
Matt Trask
@matthewtrask
What is different between this and Swagger?
The name
Matt Trask
@matthewtrask
What text formats can you use?
Matt Trask
@matthewtrask
What text formats can you use?
YAML or JSON
(we are gonna use YAML, so fair warning)
Matt Trask
@matthewtrask
What is new in OpenAPI v3.1.0?
Matt Trask
@matthewtrask
What is new in OpenAPI v3.1.0?
The Webhooks Object and integration with
JSON Schema
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
Text
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
Less time rewriting code
Better communication across teams
Quicker Iteration
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
Required Sections
Info - Metadata of the API
OpenAPI - Version for tooling
Paths - The descriptions for the endpoints
Matt Trask
@matthewtrask
Info/OpenAPI
# intentionally left blank
openapi: 3.1.0
title: Sample Pet Store App
summary: A pet store manager.
description: This is a sample server for a pet store.
termsOfService: https://example.com/terms/
contact:
name: API Support
url: https://www.example.com/support
email: support@example.com
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
version: 1.0.1
Matt Trask
@matthewtrask
Lets Break Down the Paths
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
# intentionally left blank
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
Paths are organized by endpoint, and then by HTTP Verb
Matt Trask
@matthewtrask
# intentionally left blank
# within the paths object, under the HTTP Verb for the path
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
type: integer
format: int32
- name: type
in: query
description: What type of pet to return (dog, cat, snake, droid)
required: false
schema:
type: string
Matt Trask
@matthewtrask
# intentionally left blank
# within the paths object, under the HTTP Verb for the path
responses:
'200':
description: A paged array of pets
headers:
x-next:
description: A link to the next page of responses
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
discriminator:
propertyName: pet_type
examples:
allOf:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
Remember the $ref is a reference pointer. This is a local reference in the example above
Matt Trask
@matthewtrask
# intentionally left blank
# within the paths object, under the HTTP Verb for the path
components:
schemas:
Pet:
type: object
discriminator:
propertyName: petType
properties:
name:
type: string
petType:
type: string
required:
- name
- petType
Cat: ## "Cat" will be used as the discriminator value
description: A representation of a cat
allOf:
- $ref: '#/components/schemas/Pet'
- type: object
properties:
huntingSkill:
type: string
description: The measured skill for hunting
enum:
- clueless
- lazy
- adventurous
- aggressive
required:
- huntingSkill
Dog: ## "Dog" will be used as the discriminator value
description: A representation of a dog
allOf:
- $ref: '#/components/schemas/Pet'
- type: object
properties:
packSize:
type: integer
format: int32
description: the size of the pack the dog is from
default: 0
minimum: 0
required:
- packSize
Matt Trask
@matthewtrask
Specification terms to note
$ref
reference pointer to a local resource, remote resource, or a URL
Matt Trask
@matthewtrask
$ref: local
paths:
/users:
$ref: '../resources/users.yaml'
/users/{userId}:
$ref: '../resources/users-by-id.yaml'
Matt Trask
@matthewtrask
$ref: remote
paths:
/users:
$ref: '../document.json#/resources/users.yaml'
/users/{userId}:
$ref: '../document.json#/resources/users-by-id.yaml'
Matt Trask
@matthewtrask
$ref: url
paths:
/users:
$ref: 'http://path/to/your/resource.json#myElement'
/users/{userId}:
$ref: 'http://path/to/your/resource.json#myElement'
Matt Trask
@matthewtrask
Validation reference pointers
$allOf
$anyOf
$oneOf
$not
Matt Trask
@matthewtrask
Validation reference pointers
#intentionally left blank
paths:
/pets:
patch:
requestBody:
content:
application/json:
schema:
anyOf:
- $ref: '#/components/schemas/PetByAge'
- $ref: '#/components/schemas/PetByType'
responses:
'200':
description: Updated
components:
schemas:
PetByAge:
type: object
properties:
age:
type: integer
nickname:
type: string
required:
- age
PetByType:
type: object
properties:
pet_type:
type: string
enum: [Cat, Dog]
hunts:
type: boolean
required:
- pet_type
Matt Trask
@matthewtrask
OpenAPI Initializer
https://github.com/primitivesocial/openapi-initializer
Matt Trask
@matthewtrask
OpenAPI Initializer
Matt Trask
@matthewtrask
OpenAPI Initializer
#intentionally left blank
openapi: 3.0.3
info:
title: ''
version: 0.1.0
description: 'Test API'
contact: { name: 'Laravel News', email: user@example.com, url: null }
servers:
- { url: 'http://openapi-demo.test', description: 'Local url for testing' }
tags: null
paths: null
components:
schemas: null
responses: null
headers: null
parameters: null
links: null
examples: null
Matt Trask
@matthewtrask
OpenAPI HTTP Foundation Testing
https://github.com/ostell/openapi-httpfoundation-testing
Matt Trask
@matthewtrask
OpenAPI HTTP Foundation Testing
Matt Trask
@matthewtrask
OpenAPI PSR7 Validator
https://github.com/thephpleague/openapi-psr7-validator
Matt Trask
@matthewtrask
OpenAPI PSR7 Validator
// intentionally left blank
<?php
$yamlFile = "api.yaml";
$jsonFile = "api.json";
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)
->fromYamlFile($yamlFile)
->getRequestValidator();
#or
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)
->fromJson(file_get_contents($jsonFile))
->getRequestValidator();
#or
$schema = new \cebe\openapi\spec\OpenApi(); // generate schema object by hand
$validator = (new \League\OpenAPIValidation\PSR7\ValidatorBuilder)
->fromSchema($schema)
->getRequestValidator();
$match = $validator->validate($request);
Matt Trask
@matthewtrask
Spectator
https://github.com/hotmeteor/spectator
Matt Trask
@matthewtrask
Spectator
https://github.com/hotmeteor/spectator
Matt Trask
@matthewtrask
Spectator
//intentionally left blank
<?php
use Spectator/Spectator;
class ExampleTest extends TestCase
{
/**
* A basic functional test example.
*
* @return void
*/
public function testBasicExample()
{
Spectator::using('Api.v1.json');
$response = $this->postJson('/user', ['name' => 'Sally']);
$response
->assertValidRequest()
->assertValidResponse(201);
}
}
Matt Trask
@matthewtrask
Stoplight Studio - https://stoplight.io
Matt Trask
@matthewtrask
Stoplight Studio - https://stoplight.io
Matt Trask
@matthewtrask
Stoplight Studio - https://stoplight.io
Matt Trask
@matthewtrask
https://openapi.tools
Matt Trask
@matthewtrask
You can use this for new or existing APIs
Can be used for documentation, testing, validation, SDK generation
As long as the three required objects are present, you can use as much or as little of the spec as you want!
Matt Trask
@matthewtrask
https://stoplight.io
Thanks!