PyMacaron

Star
Logo

A python microservice framework

Reference:

Overview
Quick start
Project files
OpenAPI specification
API objects
Server code
Deployment pipeline
Docker packaging
JWT authentication
Configuration
Error handling
Asynchronous execution
Database serialisation
Testing
Monitoring

PyMacaron models

API endpoints take and return objects

The core design principle of PyMacaron is to abstract all the scaffholding of setting up a Flask microservice, its routes, its deployment pipeline, etc. The only code you should have to write is the actual implementation of each endpoint.

An API endpoint in PyMacaron is a method that takes an object whose attributes are defined in the api’s swagger file, and return an other object also defined in the swagger file. Both objects are instances of PyMacaronModel.

Loading models

PyMacaron models are dynamically generated when pymacaron loads the OpenAPI specifications. This happens when starting the server:

api.load_apis(path_apis)

Using model instances

PyMacaron models come with builtin methods:

Implicit construction

The body of POST requests gets automatically converted into its corresponding PyMacaron model when passed to its endpoint method.

Assuming a POST method with the following definition:

  /v1/ask:
    post:
      summary: Ask a question
      parameters:
        - in: body
          name: body
          description: A question
          required: true
          schema:
            $ref: "#/definitions/Question"
      produces:
        - application/json
      x-bind-server: helloworld.api.do_ask
      responses:
        '200':
          description: Hello message
          schema:
            $ref: '#/definitions/Hello'

The python method ‘helloworld.api.do_ask’ will receive a ‘Question’ instance as first argument:

def do_ask(question):
    """Tada! question is an instance of the Question model"""
    assert isinstance(question, PyMacaronModel)
    assert question.get_model_name() == 'Question'

Explicit construction

Taking the openapi definition used in ‘pymacaron-helloworld’, you can either import a model after having loaded the OpenAPI files:


# Example: importing the Error model
from pymacaron.models import Error

error = Error(
    status=403,
    error='ACCESS_DENIED',
    error_description='You are not allowed to use the admin api',
)

Or use the ‘get_model()’ method for a more dynamic approach:

from pymacaron.models import get_model

Error = get_model('Error')
error = Error(status=403)

Get and set attributes

All the attributes defined in the model’s OpenAPI schema can be accessed or set as normal python instance attributes:

Via attribute name:

error.status = 500
print error.status

Or via the dictionary interface:

error['status'] = 500
print error['status']
del error['status']

Convert to and from JSON

from pymacaron.models import Error

j = error.to_json()

error = Error.from_json(j)

Model name

Get the model’s name, aka the name of the OpenAPI schema object this model is based on:

error.get_model_name()

Under the hood

PyMacaron uses bravado-core models to map an OpenAPI schema object onto a Python object instance. A PyMacaron model instance is in fact a composite object that contains an instance of the corresponding bravado-core model instance, and redirects all set/get calls on attributes to it.

Using inheritance

PyMacaron models become really powerful when used in combination with class inheritance.

Adding inheritance in OpenAPI

Use the ‘x-parent’ declaration in the OpenAPI specification to automagically make all instances of a given schema object inherit from a given python class. Here is an example taken from pymacaron-helloworld:

  Question:
    type: object
    description: A question, inheriting from a custom class
    x-parent: helloworld.models.Question
    properties:
      question:
        type: string
        description: A string

And the Question class is defined as such:

# In the file helloworld.models

class Question():

    def to_reply(self):
        return "You said: %s" % self.question

Now, any instance of ‘Question’ also has the method ‘to_reply()’:

from pymacaron.models import Question

q = Question(question='who are you?')
print q.to_reply()