Getting Started with

OpenAPI

Matt Trask

@matthewtrask

PDX PHP - 04/20/2021

Who Am I?

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 

What are we talking about?

Matt Trask

@matthewtrask

What are we talking about?

Matt Trask

@matthewtrask

What are we talking about?

Matt Trask

@matthewtrask

What are we talking about?

Matt Trask

@matthewtrask

What are we talking about?

Matt Trask

@matthewtrask

November 15th, 2006

Swagger -> OpenAPI

 

(under the Linux Foundation)

What are we talking about?

Matt Trask

@matthewtrask

What is OpenAPI?

Matt Trask

@matthewtrask

OpenAPI is a standard way to describe HTTP-based APIs through a series of collections in a JSON/YAML form.

What is OpenAPI?

Matt Trask

@matthewtrask

  • OpenAPI Specification (OAS): The industry-standard specification that outlines how OpenAPI files are structured.

 

  • OpenAPI Definition: Your actual API definition file that represents your specific API use case. This schema is machine-readable and represented in either YAML or JSON.

 

  • API Documentation: The visual, human-readable representation of the API structure. Applies HTML, CSS, and JavaScript to enable API navigation and discovery.

     
  • API Contract: An API contract IS the documentation of the API. The documentation is the place where you declare how your API will behave. In this sense it the contract between you API provider and the developers that will use it around the world.

Terms to note

Questions?

Matt Trask

@matthewtrask

New APIs or existing ones?

Questions?

Matt Trask

@matthewtrask

New APIs or existing ones?

 

Yes!

Questions?

Matt Trask

@matthewtrask

What is different between this and Swagger?

 

Questions?

Matt Trask

@matthewtrask

What is different between this and Swagger?

 

The name

Questions?

Matt Trask

@matthewtrask

What text formats can you use?

Questions?

Matt Trask

@matthewtrask

What text formats can you use?

 

YAML or JSON

 

(we are gonna use YAML, so fair warning)

Questions?

Matt Trask

@matthewtrask

What is new in OpenAPI v3.1.0?

Questions?

Matt Trask

@matthewtrask

What is new in OpenAPI v3.1.0?

 

The Webhooks Object and integration with

JSON Schema

Matt Trask

@matthewtrask

How you can use OpenAPI

Matt Trask

@matthewtrask

Design First API Development

Matt Trask

@matthewtrask

Design First API Development

Text

Matt Trask

@matthewtrask

Design First API Development Workflow

  • Generating API documentation
     
  • Automating parts of testing (APIs)
     
  • Getting early feedback on the design of the API
     
  • Ensuring API consistency especially if you have several API's
     
  • Comparing API changes across versions

Matt Trask

@matthewtrask

Design First API Benefits

Less time rewriting code

 

Better communication across teams

 

Quicker Iteration

Components of the spec

Matt Trask

@matthewtrask

Components of the spec

Matt Trask

@matthewtrask

Required Sections

 

Info - Metadata of the API

OpenAPI - Version for tooling

Paths - The descriptions for the endpoints

Components of the spec

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

Components of the spec

Matt Trask

@matthewtrask

Lets Break Down the Paths

Components of the spec

Matt Trask

@matthewtrask

Components of the spec

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

Components of the spec

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   

Components of the spec

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

Components of the spec

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

Defined Keywords/Terms

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'

Defined Keywords/Terms

Matt Trask

@matthewtrask

$ref: remote

paths:
  /users:
    $ref: '../document.json#/resources/users.yaml'
  /users/{userId}:
    $ref: '../document.json#/resources/users-by-id.yaml'

Defined Keywords/Terms

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'

Defined Keywords/Terms

Matt Trask

@matthewtrask

Validation reference pointers

$allOf

 

$anyOf

 

$oneOf

 

$not

Defined Keywords/Terms

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

Defined Keywords/Terms

How can you use this with PHP?

Matt Trask

@matthewtrask

OpenAPI Initializer

 

https://github.com/primitivesocial/openapi-initializer

How can you use this with PHP?

Matt Trask

@matthewtrask

OpenAPI Initializer

How can you use this with PHP?

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

How can you use this with PHP?

Matt Trask

@matthewtrask

OpenAPI HTTP Foundation Testing

 

https://github.com/ostell/openapi-httpfoundation-testing

How can you use this with PHP?

Matt Trask

@matthewtrask

OpenAPI HTTP Foundation Testing

How can you use this with PHP?

Matt Trask

@matthewtrask

OpenAPI PSR7 Validator

 

https://github.com/thephpleague/openapi-psr7-validator

How can you use this with PHP?

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);

How can you use this with PHP?

Matt Trask

@matthewtrask

Spectator

 

https://github.com/hotmeteor/spectator

How can you use this with PHP?

Matt Trask

@matthewtrask

Spectator

 

https://github.com/hotmeteor/spectator

How can you use this with PHP?

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);
    }
}

Tools

Matt Trask

@matthewtrask

Stoplight Studio - https://stoplight.io

Tools

Matt Trask

@matthewtrask

Stoplight Studio - https://stoplight.io

Tools

Matt Trask

@matthewtrask

Stoplight Studio - https://stoplight.io

Tools

Matt Trask

@matthewtrask

https://openapi.tools

Matt Trask

@matthewtrask

To Wrap It Up

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!

Questions?

Matt Trask

@matthewtrask

https://stoplight.io

Thanks!

Getting Started withOpenAPI

By Matt Trask

Getting Started withOpenAPI

  • 284