Create PHP SDKs from OpenAPI / Swagger

PHP SDK overview

The Speakeasy PHP SDK is designed to be easy to use and debug, and uses object-oriented programming in PHP for a robust and strongly-typed experience.

Some core features of the SDK are:

  • Class-based objects using reflection and property attributes to aid serialization.
  • A Utils package for common operations, simplifying generated code and making it easier to debug.
  • A convenient factory pattern manages the SDK configuration.
  • Support for OAuth flows and other standard security mechanisms.

While this article discusses the main features of the PHP SDK creator, for code examples with a full OpenAPI schema, please see the Speakeasy comparison article with OpenAPI Generator.

New PHP features

Since the release of PHP 8 in 2020, the language has introduced additional type features, enabling better support for OpenAPI. Some of the features we take advantage of are:

  • Union types
    private int|float $age;
  • Enums
    enum HTTPMethods: string {
    case GET = 'get';
    case POST = 'post';
    }

External libraries

The Speakeasy PHP SDK seeks to support the majority of OpenAPI / Swagger features, and as such, some features that aren’t contained in the PHP standard library.

In order to fill the gaps, we do use some external dependencies which are detailed below.

Dates

PHP has only date-time objects, not date objects. Speakeasy uses Brick\DateTime (opens in a new tab) for date support. For example:

public function deserializeDateTimeToJson(JsonDeserializationVisitor $visitor, string $data, array $type, Context $context): mixed
{
return \Brick\DateTime\LocalDate::parse($data);
}

Complex Numbers

PHP doesn’t have support for arbitrary precision numbers, so we use the Brick\Math (opens in a new tab) for complex number support.

To learn more about Speakeasy’s complex number support, please read this page.

HTTP client

The SDK uses Guzzle (opens in a new tab) to provide a default HTTP client implementation, \GuzzleHttp\Client, for making API calls, which can be overridden. The client must implement the \GuzzleHttp\ClientInterface.

To override the HTTP client, pass the client during construction:

use GuzzleHttp\Client;
$client = new Client([
'timeout' => 2.0,
]);
$sdk = SDK::builder()->setClient(
$client
)->build();

This allows for full customization of low-level features, like proxies, custom headers, timeouts, cookies, and others.

Exhaustive Type System

Speakeasy uses a combination of the built in standard library type specifications, and the phpDocumentor TypeResolver (opens in a new tab) to provide exhaustive type checking across all aspects of the generated SDK.

Serialization

Speakeasy uses JMS Serializer (opens in a new tab) for serialization due to its union support, which other serialization libraries lack.

JMS Serializer checks types received in responses at runtime, guaranteeing strong typing not only in comment annotations, but also while the application is in use and transferring data.

Files in the Speakeasy-created PHP SDK include the line declare(strict_types=1);, which causes PHP to throw a TypeError if a function accepts or returns an invalid type at runtime.

Type checking and linting

Speakeasy uses a combination of PHPStan (opens in a new tab), Laravel Pint (opens in a new tab) and Rector (opens in a new tab) in order to lint, quality control, and statically analyze our SDK.

Quality and security

Speakeasy also uses Roave Security Advisories (opens in a new tab) to ensure that our dependencies do not have any known security advisories.

Tests

PHPUnit (opens in a new tab) is included with the SDK for running tests. However, no tests are created for the SDK automatically.

PHP SDK package structure

β”œβ”€β”€ src/ # Root directory for all PHP source files
β”‚ β”œβ”€β”€ SDK.php # The main SDK class
β”‚ β”œβ”€β”€ SDKBuilder.php
β”‚ β”œβ”€β”€ SDKConfiguration.php
β”‚ β”œβ”€β”€ ... # Other SDK classes, one per tag
β”‚ β”œβ”€β”€ Models/
β”‚ β”‚ β”œβ”€β”€ Components/ # Contains data types used in requests
β”‚ β”‚ β”œβ”€β”€ Operations/ # Contains all the functions in the API
β”‚ β”‚ └── Errors/
β”‚ β”‚ └── SDKException.php # The error that all requests can throw
β”‚ └── Utils/ # Contains shared utility classes for transforming data
β”‚ └── ...
β”œβ”€β”€ docs/ # Contains Markdown files for the SDK documentation
β”‚ └── ...
β”œβ”€β”€ composer.json # Configuration for PHP Composer
└── vendor # External dependencies

PHP SDK data types and classes

The Speakeasy PHP SDK uses native types wherever possible:

  • string
  • DateTime
  • int
  • float
  • bool

Where no native data type is available, we fall back to using libraries:

  • Brick\DateTime\LocalDate
  • Brick\Math\BigInteger
  • Brick\Math\BigDecimal

Generated classes are standard PHP classes with public properties and use attributes and reflection to help guide serialization.

Parameters

When configured, Speakeasy will include up to a specified number of parameters directly in the function signatures, rather than provided as an object to be passed to the operation methods.

The maximum number of parameters to be placed in the method signature is set in the maxMethodParams option in the gen.yaml file. If maxMethodParams is not set or set to 0, no method parameters will be added.

Errors

The Speakeasy PHP SDK returns errors by throwing the appropriate error class as part of the SDK call. The caller should wrap requests in a try block to handle the error in the response.

User agent strings

The PHP SDK includes a user agent (opens in a new tab) string in all requests, which can be leveraged to track SDK usage amongst broader API usage. The format is as follows:

speakeasy-sdk/php {{SDKVersion}} {{GenVersion}} {{DocVersion}} {{PackageName}}
  • SDKVersion is the version of the SDK, defined in gen.yaml and released
  • GenVersion is the version of the Speakeasy generator
  • DocVersion is the version of the OpenAPI document
  • PackageName is the name of the package defined in gen.yaml

Feature examples

Let’s take a look at how OpenAPI features are mapped to PHP code. We’ll use snippets from the PetStore 3.1 YAML schema file from the Swagger editor (opens in a new tab). If you’re not familiar with the example, it provides operations to manage users, customers, pets, and orders for pets in a hypothetical pet store.

Tags

Each tag in the schema becomes one file of top-level operations, such as Pet.php, Store.php, and User.php for:

tags:
- name: pet
description: Everything about your Pets
externalDocs:
description: Find out more
url: http://swagger.io
...

Security

The pet store schema uses API key security and OAuth 2.0:

/pet/{petId}:
security:
- api_key: []
- petstore_auth:
- write:pets
- read:pets
...
components:
securitySchemes:
petstore_auth:
type: oauth2
flows:
implicit:
authorizationUrl: https://petstore31.swagger.io/oauth/authorize
scopes:
write:pets: modify pets in your account
read:pets: read your pets
api_key:
type: apiKey
name: api_key
in: header

The PHP SDK will create a security class you can call with either scheme:

use OpenAPI\OpenAPI\Utils\SpeakeasyMetadata;
class GetPetByIdSecurity
{
/**
*
* @var ?string $apiKey
*/
#[SpeakeasyMetadata('security:scheme=true,type=apiKey,subtype=header,name=api_key')]
public ?string $apiKey = null;
/**
*
* @var ?string $petstoreAuth
*/
#[SpeakeasyMetadata('security:scheme=true,type=oauth2,name=Authorization')]
public ?string $petstoreAuth = null;
/**
* @param ?string $apiKey
* @param ?string $petstoreAuth
*/
public function __construct(?string $apiKey = null, ?string $petstoreAuth = null)
{
$this->apiKey = $apiKey;
$this->petstoreAuth = $petstoreAuth;
}
}
# Example call:
$requestSecurity = new Operations\GetPetByIdSecurity();
$requestSecurity->apiKey = '<YOUR_API_KEY_HERE>';
$response = $sdk->pet->getPetById($requestSecurity, 504151);

Only implicit flow OAuth is currently supported.

Enums

Speakeasy uses native types in PHP 8 for enums.

enum Status: string
{
case Available = 'available';
case Pending = 'pending';
case Sold = 'sold';
}

Typed parameters

Below is an example in the schema of an array of strings.

/pet/findByTags:
get:
operationId: findPetsByTags
parameters:
- name: tags
in: query
required: false
explode: true
schema:
type: array
items:
type: string

The PHP SDK types the parameter in a DocBlock.

/** Finds Pets by tags
* @param ?array<string> $tags
* @return Operations\FindPetsByTagsResponse
* @throws \OpenAPI\OpenAPI\Models\Errors\SDKException
*/
public function findPetsByTags(?array $tags = null,): Operations\FindPetsByTagsResponse {

You can use oneOf in a schema like this:

Pet:
type: object
properties:
age:
oneOf:
- type: integer
- type: string

The age property will be typed as a union in PHP:

/**
*
* @param int|string|null $age
*/

Unsupported features

Speakeasy does not support the following OpenAPI features in PHP:

  • XML requests and responses
  • OAuth 2.0 flows other than implicit flow
  • SDK hooks

As PHP SDK creation is still an beta release, not all extension attributes (x-speakeasy) work. For example, open enums and automatic retries are not supported.