Upsun

Upsun official PHP SDK

The open-source PHP client for the Upsun API: generated from the OpenAPI spec, with a handwritten developer-facing layer.

Role
Development, in the Advocacy team: full API coverage, facades, tests, release
Period
Jul 2025 – ongoing · Upsun
Stack
  • PHP 8.1+
  • OpenAPI Generator
  • Mustache
  • PHPUnit
  • GitHub Actions
  • Composer

Context

The Upsun API is rich (organizations, projects, environments, variables, deployments…), but calling it from PHP meant writing HTTP requests, authentication and models yourself. It needed an official, complete SDK that stays current with no effort as the API evolves.

What I built

Starting from the initial skeleton set up by an Advocacy teammate, I built most of the SDK: full API coverage, the facades, the tests and the Packagist release. The architecture has two layers:

  • A generated layer built with OpenAPI Generator from the official OpenAPI spec, served by Meta-Upsun: one model per schema, one class per endpoint group. It covers 100% of the public API.
  • A handwritten "Tasks" layer, the public interface: $client->projects->create(...), $client->organizations->listProjects(...), with named arguments, strict types and readonly properties. Developers never touch the generated models.

Around it:

  • Spec pre-processing in PHP before generation: Mustache templates only handle simple tests, so transformations (adding x-* fields, fixes) happen upstream, in testable code.
  • Daily sync: a GitHub workflow compares the published spec with the local copy and opens a pull request when they differ.
  • Alignment with the Node.js SDK: same method names and signatures, enforced by a checking tool I wrote that reports any divergence between the two SDKs.
  • 476 PHPUnit tests (over 3,500 assertions) and full PHPDoc for IDE autocompletion.
  • Distributed on Packagist: composer require upsun/upsun-sdk-php. Source code on GitHub.
  • Searchable documentation of the architecture and code on DeepWiki.

Technical challenges

  • A real-world spec is never perfect: incomplete schemas, ambiguous types. Pre-processing fixes them without touching the official source, and every fix is versioned.
  • Separating generated from maintained code: the Tasks layer shields users from changes in the generated code. An API change doesn't break their code.

Results

Further reading

← Back to the portfolio