Generating PHP library code from OpenAPI

I’m working with a bunch of OpenAPI specs now I am working for Nexmo and so far I’m loving working with API descriptions. OpenAPI is the next iteration of what used to be called “Swagger”, a machine-readable way to describe your API and from that description create docs, code libraries, tests, and all sorts. Today’s post is a quick writeup of how I generated some PHP code so that I can refer back to this next time I want to do it!

Nexmo currently has a bunch of hand-built libraries but I wondered if we could generate some of the backend legwork bits – this would also allow us to regenerate them when things change (useful for the APIs that are still under development). To this end, I used https://github.com/openapitools/openapi-generator and it was an easy experience.
f
Good: they supply the whole thing in a docker image so installation is simple!

Better: there are great docs on what I need to to do run the code. I was looking at the Secret Management API for Nexmo (so you can rotate your secrets programmatically and in a sane way), the definition is on GitHub so my command was like this:

docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli generate \
  -i https://raw.githubusercontent.com/Nexmo/api-specification/master/definitions/account/secret-management.yml \
  -g php -o /local/out/php

Best: Along with my generated code (in out/php/ relative to where I ran this command from), this project generates a README.md file. A readme, people! It even has accurate instructions of how to use the code that was generated!

Here’s the PHP example for posterity: calling the endpoint that receives all current secrets (actually just the ID and timestamp, not the actual secrets because that would be quite the opposite of secure)

<?php
require "out/php/vendor/autoload.php";

$config = OpenAPI\Client\Configuration::getDefaultConfiguration()
    ->setUsername(NEXMO_API_KEY)
    ->setPassword(NEXMO_API_SECRET);

$client = new OpenAPI\Client\Api\DefaultApi(new GuzzleHttp\Client(), $config);
$inline_object = new \OpenAPI\Client\Model\InlineObject();

try {
    $result = $client->retrieveSecrets(NEXMO_API_KEY, $inline_object);
    print_r($result);
} catch (Exception $e) {
    echo 'Exception when calling DefaultApi->retrieveSecrets: ', $e->getMessage(), PHP_EOL;
}

Looks pretty good to me, it knows how to handle the Basic Auth that this API uses, and methods have been created for each of the endpoints in my API Specification (there is also documentation! Wow!). Are you generating code from the v3 OpenAPI specs? I’d love to hear your tips, tricks and stories from the front – leave me a comment.

4 thoughts on “Generating PHP library code from OpenAPI

  1. I’m guessing this is the same generator running on the online swagger/openapi editor https://editor.swagger.io/ It’s a really quick way in to trying these things out.

    Now, what I’m finding is that the assumptions made in the generator are all wrong for my use-case today. I will have to fork it to make the changes (PRO: I *can* fork it to make changes, which is awesome). So, to ditch the baked-in Guzzle, not that I wouldn’t be using it in many instances, but moving to PSR-7+PSR-17+PSR-18 is where I am heading.

    • When using the generator, you have full control to override all the templates used to generate the code. I use it to create PSR-7 messages and accept any PSR-18 client, and it works great.

      When you first posted here, you could only define overrides for the templates that the generator already defines for tour destination language. Since version 5.1.0 (or thereabouts) you now have the ability to add your own templates and define the destination structure that they go into. That is immensely powerful.

      The way it works is that the generator reads the OpenAPI description and creates a massive data structure with cuts through the components and operations in many ways. The templates use mustache, with virtually no logic in them (just looks over data, and conditions on whether data is there or not). The data structure is digest enough to allow you to do a lot when generating. But you have to think like moustache templates – any logic you want to include, needs to be generated in code so that it can run at runtime, not while you generate the code.

      • Hello Jason,

        How do you define the destination structure of the generated files please?
        All the model classes are generated in a unique folder which is not really useful.
        If you have an implementation example it would be great!
        Thanks :)

  2. Pingback: rrrhys

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

This site uses Akismet to reduce spam. Learn how your comment data is processed.