Type System

MorpFW CRUD & object management revolves around the idea of resource type. A resource type represents a data model and its respective fields. Resource type definition consist of a Schema, a Collection and a Model class. Collection is very similar to the concept of database table, and model is very similar to a row. Model have a Schema which defines the columns available in the Model.

When designing your application, it helps to think and model your application around the concept of resource type model and collections because views are attached to them.

Schema

Resource type schema in MorpFW is defined through new python 3.7 dataclass library.

Schema in MorpFW is used for:

  • data validation of JSON data on create/update REST API

  • data validation on dictionary that is used to create a new instance of resource.

  • generating JSON schema for publishing in REST API

When defining a schema, it is good that you inherit from morpfw.Schema as it defines the core metadata required for correct function of the framework.

import morpfw
import typing
from dataclasses import dataclass

@dataclass
class MySchema(morpfw.Schema):

    field1: typing.Optional[str] = None
    field2: typing.Optional[str] = 'hello world'

Due to the nature of dataclass inheritance, your field definition must include default values, and if it does not have any, you should define the field with typing.Optional data type with a default value of None

Model

Model is the object that is published on a MorpFW path. MorpFW base model class provides the necessary API for model manipulation such as update, delete, save and other model manipulation capabilities of MorpFW.

class morpfw.interfaces.IModel(request: Request, collection: ICollection, data: dict)

Model is a representation of a data object. It provide a common set of API which is then delegated down to the storage provider.

Model is subscriptable and you can use it like a dictionary to access stored data.

Parameters:
  • request – the request object

  • storage – storage provider

  • data – initial data on this model

after_blobput(field: str, blob: IBlob) None

Triggered after BLOB is stored

after_created() None

Triggered after resource have been created

after_updated() None

Triggered after resource have been created

before_blobdelete(field: str) None

Triggered before BLOB is deleted

If the return value is False-ish, delete will be prevented

before_blobput(field: str, fileobj: BinaryIO, filename: str, mimetype: Optional[str] = None, size: Optional[int] = None, encoding: Optional[str] = None) None

Triggered before BLOB is stored

before_delete() bool

Triggered before deleting resource

If the return value is False-ish, delete will be prevented

before_update(newdata: dict) None

Triggered before updating resource with new values

abstract delete()

Delete model

abstract delete_blob(field: str)

Delete blob

abstract get_blob(field: str) IBlob

Return blob

abstract json() dict

Convert model to JSON-safe dictionary

Generate links for this model

abstract put_blob(field: str, fileobj: BinaryIO, filename: str, mimetype: Optional[str] = None, size: Optional[int] = None, encoding: Optional[str] = None) IBlob

Receive and store blob object

abstract rulesprovider()

Return pluggable business rule adapter for this model

abstract save()

Persist model data into backend storage

abstract set_initial_state()

Initialize default statemachine state for this model

abstract statemachine()

Return PyTransition statemachine adapter for this model

abstract update(newdata: dict, secure: bool)

Update model with new data

abstract xattrprovider()

Return extended attributes provider for this model

blob_fields: List[str]

List of blob field names allowed on this model

blobstorage_field: str

Field name on the model data which will be storing blob references

data: IDataProvider

Data provider

delete_view_enabled: bool

When set to True, will enable DELETE view to delete model

hidden_fields: list

List of fields that should be hidden from output

identifier: str

url identifier for this model

linkable: bool

Set whether object is linkable or not. If an object is linkable, its json result will have links attribute

abstract property schema: Type[ISchema]

The dataclass schema which this model will be using

update_view_enabled: bool

When set to True, will enable PATCH view to update model

uuid: str

uuid of this model

Collection

Collection is the container for Model objects. Collection manages the single type of Model and and provide collection level Model object management API such as create, search and aggregate.

class morpfw.interfaces.ICollection

Collection provide an API for querying group of model from its storage

abstract aggregate(query: Optional[dict] = None, group: Optional[dict] = None, order_by: Optional[tuple] = None) List[IModel]

Get aggregated results

: param query: Rulez based query : param group: Grouping structure : param order_by: Tuple of (field, order) where order is

'asc' or 'desc'

: todo: Grouping structure need to be documented

before_create(data: dict) None

Triggered before the creation of resource

abstract create(data: dict) IModel

Create a model from data

abstract get(identifier) IModel

Get model by url identifier key

abstract get_by_uuid(uuid: str) IModel

Get model by uuid

abstract json() dict

JSON-safe dictionary representing this collection

Links related to this collection

abstract search(query: Optional[dict] = None, offset: int = 0, limit: Optional[int] = None, order_by: Optional[tuple] = None, secure: bool = False) List[IModel]

Search for models

Filtering is done through rulez based JSON/dict query, which defines boolean statements in JSON/dict structure.

: param query: Rulez based query : param offset: Result offset : param limit: Maximum number of result : param order_by: Tuple of (field, order) where order is

'asc' or 'desc'

: param secure: When set to True, this will filter out any object which

current logged in user is not allowed to see

: todo: order_by need to allow multiple field ordering

Storage

Model and collection gets their data from a storage provider. It abstracts the interface to storage backends, allowing custom storage backends to be implemented.

class morpfw.interfaces.IStorage(request: Request, blobstorage: Optional[IBlobStorage] = None)

Aggregateable storage

abstract aggregate(query: Optional[dict] = None, group: Optional[dict] = None, order_by: Union[None, list, tuple] = None) list

return aggregation result based on specified rulez query and group

abstract create(data: dict) IModel

Create a model from submitted data

abstract delete(identifier, model)

delete model data

abstract get(identifier) Optional[IModel]

return model from identifier

abstract get_by_id(id) Optional[IModel]

return model from internal ID

abstract get_by_uuid(uuid) Optional[IModel]

return model from uuid

abstract search(query: Optional[dict] = None, offset: Optional[int] = None, limit: Optional[int] = None, order_by: Union[None, list, tuple] = None) Sequence[IModel]

return search result based on specified rulez query

abstract update(identifier, data)

update model with values from data

BlobStorage

Storage provider may have a BLOB storage backend implemented which will handle the management of BLOBs

class morpfw.interfaces.IBlobStorage
abstract delete(uuid: str)

Delete blob data

abstract get(uuid: str) Optional[IBlob]

Return blob data

abstract put(field: str, fileobj: BinaryIO, filename: str, mimetype: Optional[str] = None, size: Optional[int] = None, encoding: Optional[str] = None, uuid: Optional[str] = None) IBlob

Receive and store blob data