While working with Adding Support to OpenAPI to Kinto, one of the features that most called my attention was the support for automated client generation. This may save a lot of time and effort for developers which may want to code on client languages that are currently not supported by the Kinto project.

On this quick tutorial I'm going to show how to create clients using the Swagger Code Generator API and use some of it's features. If you plan to follow this in detail, I recommend downloading this example repository with the code and documentation examples used. In some parts I'll assume some familiarity with Kinto HTTP API. For more information, please check the Oficial Documentation or the OpenAPI interactive documentation. Some Python and PHP basics are also useful.

Generating a Python client

To begin with our client generation. We can install the release version of swagger-codegen and follow its instructions on how to generate a client. But wait! What if I'm lazy and don't to generate the client myself? The code generator has it's own API for creating clients (would be surprising if they don't). Let's try it!

echo '{"swaggerUrl": "https://raw.githubusercontent.com/gabisurita/kinto/631-swagger/swagger.yaml"}' \
| http post https://generator.swagger.io/api/gen/clients/python --verify=no
HTTP/1.1 200 OK
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, POST, DELETE, PUT
Access-Control-Allow-Origin: *
Connection: close
Content-Length: 139
Content-Type: application/json
Date: Thu, 15 Dec 2016 23:08:18 GMT
Server: Jetty(9.2.9.v20150224)

{
    "code": "9351bd60-8f62-42c6-b865-388d6938d2a6",
    "link": "https://generator.swagger.io/api/gen/download/9351bd60-8f62-42c6-b865-388d6938d2a6"
}

We now have a link to our generated client, let's download and unzip it. You should replace the download link with the one you've got on the last request. The links generated by the API can only be used once.

http get https://generator.swagger.io/api/gen/download/9351bd60-8f62-42c6-b865-388d6938d2a6 \
--download --verify=no
unzip python-generated-client.zip

Testing the generated client

Weeeeeeee!!! We've got our client! Try exploring the code and reading the client documentation. Notice that the generated client is a almost ready Python package, so we can easily deploy it or install it with pip. Now, let's create a directory and setup and activate a virtualenv for an app that will use the client.

mkdir python-app
virtualenv python-app/venv
source python-app/venv/bin/activate

We can now install our client with pip.

pip install -e python-client

We may start coding our app logic by creating an app.py file.

import swagger_client

# Configure HTTP basicAuth
swagger_client.configuration.username = 'Gabi'
swagger_client.configuration.password = 'ILoveCats'

# create a client instance
client = swagger_client.KintoApi()

# Our bucket data (one way is to define it as a dict)
buck = {
    'data': {
        'id': 'openapi',
        'description': 'OpenAPI bucket'
    },
    'permissions': {
        'read': ['system.Everyone']
    }
}

# Create our bucket
client.create_bucket(bucket=buck)

# Our collection data (we can define it as a Collection instance)
col = swagger_client.Collection()
col.data = {'description': 'What we know about our clients'}
col.permissions = {'write': ['system.Everyone']}

# Create or update our collection
col = client.update_collection('openapi', 'clients', collection=col)

# Create a few records by batch
batch = swagger_client.Batch()

batch.defaults = {
    'method': 'POST',
    'path': '/buckets/openapi/collections/clients/records'
}

batch.requests = [
    {'body': {'data': {'id': 'python', 'tested': False}}},
    {'body': {'data': {'id': 'php', 'tested': True}}},
    {'body': {'data': {'id': 'haskell', 'tested': False}}}
]

# Get our created records. What if we also want the headers?
result = client.get_records_with_http_info('openapi', 'clients')
data, status, headers = result
print(data)

# But wait! There something there that sould be patched!
record = client.get_record('openapi', 'clients', 'python')
record.data['tested'] = True
result = client.patch_record('openapi', 'clients', 'python', record=record)

# Let's get only the changes
result = client.get_records('openapi', 'clients', since=headers['ETag'])
print(result)

Now we can run our app. This looks nice, doesn't it? But wait a minute! Why would we need a generated Python client if we already have our fancy kinto-http.py client? We actually may never use it, but this helped me on managing the client generator less friendly languages, as we will see at out next example, a PHP client.

Generating a PHP client

I will go fast with the generation steps this time. Don't forget to replace the download command with your own link.

echo '{"swaggerUrl":"https://raw.githubusercontent.com/gabisurita/kinto/631-swagger/swagger.yaml"}' \
| http post https://generator.swagger.io/api/gen/clients/php --verify=no

http get https://generator.swagger.io/api/gen/download/9351bd60-8f62-42c6-b865-388d6938d2a6 \
--download --verify=no

unzip php-generated-client.zip

PHP doesn't support keyword arguments by default, so we need to check the documentation on how to pass parameters to our methods, but don't worry, it's quite intuitive. Let's see for example the create_bucket Operation entry.

createBucket

SwaggerClientModelBucket createBucket($bucket, $if_match, $if_none_match)

So now we have an idea on how the operation looks like. You may want to check the others too. Managing packages in PHP is a lot more tricky than in Python, so we'll skip it for this example. Let's suppose we want to share our app integrated to the client, so we can just create an app.php file on the root of our just generated client. Now may we try some PHP.

<?php
require_once('SwaggerClient-php/autoload.php');

// Configure HTTP basic authorization: basicAuth
$config = Swagger\Client\Configuration::getDefaultConfiguration();
$config->setUsername('Gabi');
$config->setPassword('IReallyHatePHP');  // Please keep it a secret

// Create an API instance to make requests
$api_instance = new Swagger\Client\Api\KintoApi();

// Our Bucket data
$bucket = array(
    'data' => array(
        'id' => 'php_bucket',
        'my_precious' => True
    )
);

// Create a bucket
$api_instance->createBucket($bucket);

// Create a collection 'Good Moments' under the bucket
$api_instance->updateCollection('php_bucket', 'good_memories');

// Create some records
$record = array('data' => array('description' => 'Release of PHP 5.5'));
$api_instance->createRecord('php_bucket', 'good_memories', $record);

$record = array('data' => array('description' => 'Stop coding PHP'));
$api_instance->createRecord('php_bucket', 'good_memories', $record);

$record = array('data' => array('description' => 'My PC coded PHP for me'));
$api_instance->createRecord('php_bucket', 'good_memories', $record);

// Fetch all our records
$result = $api_instance->getRecords('php_bucket', 'good_memories');
print_r($result);

// Enough of PHP
$result = $api_instance->deleteBucket('php_bucket');
?>

Yeeey! We actually used Kinto with PHP with almost no effort! Isn't this amazing (despite the fact that we just coded PHP)? You may run the and check it's outputs.

This tutorial may be extended once the OpenAPI specification is merged to the Kinto repository. If you want to try an specific language (like Haskell, I really want to try Haskell), you may also suggest it for me and we can try this adventure together! See you!