Five Minutes from Machine Learning to RESTful API

The benefits of Connexion: Zalando’s open source API-First framework

photo of Elvin Valiev
Elvin Valiev

Software Engineer

Posted on Feb 15, 2018

The benefits of Connexion: Zalando’s open source API-First framework

In this article, I will show how quick and simple it can be to create a RESTful API for a machine learning model using Zalando’s open source Swagger/OpenAPI First framework called Connexion. Official documentation describes Connexion as the following: “Connexion is a framework on top of Flask that automagically handles HTTP requests based on OpenAPI 2.0 Specification (formerly known as Swagger Spec) of your API described in YAML format.”

That means you define your API using swagger definition, and Connexion maps the endpoints to your Python functions. Connexion guarantees that your API works as you defined it.

Connexion “automagically” takes care of the following tasks for you:

  • Provides a web Swagger Console UI for the live documentation and plays around with the API’s endpoints through it
  • OAuth 2 token-based authentication
  • API versioning
  • Automatic serialization of payloads
  • Validates requests and endpoint parameters automatically, based on your specification

This is a great way to get your machine learning model working on production with very little effort. In order to get started using Connexion we will follow the next steps:

1. Training the Classifier

For the sake of example, let’s first create a simple Scikit learn classifier. We are going to train a very simple news classifier using a “20 newsgroups” data set.

null

After training the model we will be pickling it to be used by our REST API.

2. Creating the REST API

Getting started with Connexion is very easy. A sample application with nice documentation can be found in this repository: https://github.com/hjacobs/connexion-example

2.1 Installing Connexion

$ pip install connexion

2.2 Defining our API

swagger: '2.0'
info:
  title: News classifier
  version: "0.1"
consumes:
  - application/json
produces:  - application/json
paths:
  /predictions:
    post:
      operationId: app.post_predictions
      summary: Predicts categories of the given news articles
      parameters:
        - name: query
          in: body
          schema:
            type: array
            items:
              $ref: '#/definitions/Query'
      responses:
        200:
          description: Returns predicted categories
          schema:
            type: array
            items:
              $ref: '#/definitions/Prediction'

definitions:
  Prediction:
      type: object
      required:
        - category
        - text
      properties:
        category:
          type: string
          description: Predicted category of a news article
          example: "talk.politics.misc"
          readOnly: true
        text:
          type: string
          description: query text
          example: "Ronaldo scored 3 goals against Napoli"
          readOnly: true
  Query:
     type: object
     required:
       - text
     properties:
       text:
         type: string
         description: text to predict

We have an endpoint named/predictions. It will receive list of Query models as an input and will produce a list of Prediction models. We save this file as ‘swagger.yaml’.

2.3Import connexion and registering our Swagger file:

import connexion
app = connexion.App(__name__)app.add_api('swagger.yaml')

2.3 Running the application behind a simple server using  gevent

if __name__ == '__main__':
     app.run(port=8080, server='gevent')

2.5 Importing our classifier

from sklearn.externals import joblib
classifier = joblib.load('./classifier/model.pkl')

2.6 Defining our prediction endpoint

def post_predictions(query):
    predictions = []
    for item in query:
        text = item['text']
        category = classifier.predict([text])[0]
        predictions.append({"category": category, "text": text})
    return predictions

As you can see here, method name corresponds to “operationId” property in our swagger definition. And that’s all. After running our app using the command:

./app.py

...we now can test our API using simple curl request:

➜  ~ curl --request POST \
--url http://localhost:8080/predictions \
--header 'content-type: application/json' \
--data '[{"text": "Angela Merkel just walked into her fourth term as chancellor of Germany.Her party, the Christian Democrats (CDU), picked up 32.5 percent of the votes in Sunday's election, according to the first exit polls issued at 6 pm German local time."}]'
[
{
"category": "talk.politics.misc",
"text": "Angela Merkel just walked into her fourth term as chancellor of Germany.Her party, the Christian Democrats (CDU), picked up 32.5 percent of the votes in Sunday's election, according to the first exit polls issued at 6 pm German local time."
}
]

And there we are! With a few lines of code we created a running REST API for our machine learning model.

We can even further experiment with and explore other capabilities of Connexion.

Using Swagger UI:

If you open your browser and go to http://localhost:8080/ui/ you will be able to see the Swagger UI.

null

Here, you can play around with and test your API, send sample requests, test input validation, etc.

Using a different Server Backend:

By default, Connexion uses Flask server but we can also use Tornado or gevent as a backend. To use Tornado:

app.run(port=8080, server='tornado')

OAuth 2 Authentication and Authorization:

If we set TOKENINFO_URL environment variable or include ‘x-tokenInfoUrl’ in our swagger file, Connexion will secure our endpoints. More information on this can be found on this repo.

Conclusion

By writing the API spec first you can easily get your REST API up and running with a little effort using Connexion. And additionally, allows features like, automatic request validation, Oauth 2 token based authentication,  json serialization (if your specification defines that an endpoint returns json) and API versioning.

This piece was originally published on Medium. Want to work with people like Elvin? Check out our jobs page!

Resources:

Source code of the example : https://github.com/elvinx/connexion-example Link to Connexion github repo : https://github.com/zalando/connexion Connexion official documentation: https://connexion.readthedocs.io/en/latest/