PolyMicro
PolyMicro is a Model Based Rest API system written around PynamoDB
and Marshmallow
for
request and response marshalling and designed to work interchangeably with various different
deployments.
Installation
Installation is simple.
pip install polymicro
See our example below for how easy it is to get up and runnning with polymicro.
Road Map
In the future we would like to bring the following features to PolyMicro.
- Swappable Data Backends (For instance, supporting SQL Alchemy, etc.)
- Configurable Response Types (Serializing to things other than json)
Example
It is as simple as one... two.... three.... (four).
Step 1: Create your PolyMicro app
from flask import Flask
from polymicro import PolyMicro
def get_request_user(self):
# Get the user however you want. If there is no user for the request, return None
return 'abc123'
app = Flask(__name__)
pm = PolyMicro(app, req_user_func=get_request_user)
This step revolves around setting the basics of the application. You need to create a flask app as you would do in any other flask application. Then we are going to create a function that tells PolyMicro how to get user information from the given request and pass that into the creation of our polymicro app.
Step 2: Create your PynamoDB Model
from datetime import datetime
from uuid import uuid4
from pynamodb.models import Model
from pynamodb.attributes import UnicodeAttribute, BooleanAttribute, UTCDateTimeAttribute
class Todo(Model):
class Meta:
table_name = 'todos'
owner = UnicodeAttribute(hash_key=True)
uuid = UnicodeAttribute(range_key=True, default=lambda: str(uuid4()))
creation_date_time = UTCDateTimeAttribute(default=datetime.utcnow)
text = UnicodeAttribute()
done = BooleanAttribute(default=False)
due_date_time = UTCDateTimeAttribute(null=True)
PynamoDB is a tool to write models in DynamoDB similar to an ORM. We use it to define information.
Step 3: Define Permissions (Optional)
from polymicro.permissions import Permission
class TodoPermission(Permission):
def has_object_permission(self, user, method: str, instance):
return instance.owner == user.uuid
def has_permission(self, user, method: str):
return 'administrator' in user.permissions or 'therapist' in user.permissions
Permissions are simple sets of rules from which you can define weather or not a user can access a particular resource and object. Return false if the permission proves the user cannot use the object or the method and true otherwise.
Step 4: Define the Resource
from polymicro import ModelResource, Create, List, Retrieve, Update, Delete
class TodoResource(ModelResource, Create, List, Retrieve, Update, Delete):
model = Todo
route = 'todo'
permissions = (TodoPermission)
dump_only = ('creation_date_time', 'owner', 'uuid')
required = ('text', )
def list(self, user, pagination_key=None, limit=25):
return Todo.query(user.uuid, last_evaluated_key=pagination_key, limit=limit)
def create(self, req: dict, user):
req['owner'] = user.uuid
return super().create(req, user)
TodoResource(pm)
We can define resources by composition. So first, define a class that extends from ModelResource
. This class
will form the base of the functionality that we will want to implement. Next, extending from the Create
, List
,
Retrieve
, Update
, and Delete
class will implement standard versions of those functions. You can also override the
function.
These functions can return several different things.
One of these:
- A single or collection of your model.
- Anything that is JSON serializable
And optionally these:
- A HTTP status code as an integer.
- A string -> string dictionary representing extra headers.
- For the list operation, a 4th item that allows for a pagination key to be returned in the response for pagination.
Below are some examples:
# Returning all three.
def retrieve(self, instance, user):
return instance, 418, {'Extra': 'Something-Super-Secret'}
# Returning instance and status code
def retrieve(self, instance, user):
return instance, 418
# Return just the single instance.
def retrieve(self, instance, user):
return instance
# The list operation allows for a 4th item that allows for a pagination key that can be returned back later.
def list(self, user, pagination_key=None, limit=25):
items = Todo.query(user.uuid, last_evaluated_key=pagination_key, limit=limit)
return items, 418, {}, 'some-key'