Type System REST API¶
For each published resource type, several endpoints are automatically made available by the framework to use. This is done through Morepath view inheritance on model/collection objects.
Lets take for example the following resource type definition:
import typing
from dataclasses import dataclass, field
import morpfw
import morpfw.sql
import sqlalchemy as sa
from morpfw.authz.pas import DefaultAuthzPolicy
from morpfw.crud import permission as crudperm
from morpfw.permission import All
class AppRoot(object):
def __init__(self, request):
self.request = request
class App(DefaultAuthzPolicy, morpfw.SQLApp):
pass
@App.path(model=AppRoot, path="/")
def get_approot(request):
return AppRoot(request)
@App.permission_rule(model=AppRoot, permission=All)
def allow_all(identity, context, permission):
""" Default permission rule, allow all """
return True
@App.json(model=AppRoot)
def index(context, request):
return {"message": "Hello World"}
@dataclass
class PageSchema(morpfw.Schema):
body: typing.Optional[str] = field(default=None, metadata={"title": "Body"})
value: typing.Optional[int] = field(default=0, metadata={"title": "Value"})
class PageCollection(morpfw.Collection):
schema = PageSchema
class PageModel(morpfw.Model):
schema = PageSchema
blob_fields = ['attachment']
# SQLALchemy model
class Page(morpfw.sql.Base):
__tablename__ = "test_page"
body = sa.Column(sa.Text())
value = sa.Collection(sa.Integer())
class PageStorage(morpfw.SQLStorage):
model = PageModel
orm_model = Page
@App.storage(model=PageModel)
def get_storage(model, request, blobstorage):
return PageStorage(request, blobstorage=blobstorage)
@App.path(model=PageCollection, path="/pages")
def get_collection(request):
storage = request.app.get_storage(PageModel, request)
return PageCollection(request, storage)
@App.path(model=PageModel, path="/pages/{identifier}")
def get_model(request, identifier):
col = get_collection(request)
return col.get(identifier)
class PageStateMachine(morpfw.StateMachine):
states = ["new", "pending", "approved"]
transitions = [
{"trigger": "approve", "source": ["new", "pending"], "dest": "approved"},
{"trigger": "submit", "source": "new", "dest": "pending"},
]
@App.statemachine(model=PageModel)
def get_pagemodel_statemachine(context):
return PageStateMachine(context)
@App.permission_rule(model=PageCollection, permission=All)
def allow_collection_all(identity, context, permission):
""" Default permission rule, allow all """
return True
@App.permission_rule(model=PageModel, permission=All)
def allow_model_all(identity, context, permission):
""" Default permission rule, allow all """
return True
@App.typeinfo(name="test.page", schema=PageSchema)
def get_typeinfo(request):
return {
"title": "Test Page",
"description": "",
"schema": PageSchema,
"collection": PageCollection,
"collection_factory": get_collection,
"model": PageModel,
"model_factory": get_model,
}
Collection¶
- GET /pages¶
Display page collection metadata
Example Response:
HTTP/1.1 200 OK Content-Type: application/json { "schema": { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "id": { "type": "integer" }, "uuid": { "type": "string" }, "creator": { "type": "string" }, "created": { "type": "string", "format": "date-time" }, "modified": { "type": "string", "format": "date-time" }, "state": { "type": "string" }, "deleted": { "type": "string", "format": "date-time" }, "blobs": { "type": "object" }, "xattrs": { "type": "object" }, "body": { "type": "string" }, "value": { "type": "integer" } }, "additionalProperties": true }, "links": [ { "rel": "create", "href": "http://localhost:5000/pages", "method": "POST" }, { "rel": "search", "href": "http://localhost:5000/pages/+search" } ] }
- POST /pages¶
Create new page
Example request:
POST /pages/ HTTP/1.1 Content-Type: application/json { "body": "Hello world" }
Example response:
HTTP/1.1 200 OK Content-Type: application/json { "data": { "id": 1, "uuid": "ea31ebb4eb814572b2cbfc2d30fac7f2", "creator": "285969eefd7547d38fb3a5d06996f93e", "created": "2019-01-29T08:37:48.653715", "modified": "2019-01-29T08:37:48.653715", "state": null, "deleted": null, "body": "Hello world", "value": 0 }, "links": [ { "rel": "self", "href": "http://localhost:5000/pages/ea31ebb4eb814572b2cbfc2d30fac7f2" }, { "rel": "update", "href": "http://localhost:5000/pages/ea31ebb4eb814572b2cbfc2d30fac7f2", "method": "PATCH" }, { "rel": "delete", "href": "http://localhost:5000/pages/ea31ebb4eb814572b2cbfc2d30fac7f2", "method": "DELETE" } ] }
- GET /pages/+aggregate¶
The aggregate API allows you to query for aggregate of fields from your resource dataset.
- Query Parameters:
group – grouping structure
q –
rulez
dsl based filter queryorder_by – string in
field:order
format whereorder
isasc
orasc
andfield
is the field name.
Example request:
from urllib.parse import urlencode import json import requests qs = urlencode({ 'group': ("count:count(uuid), year:year(created), month:month(created)," "day:day(created), sum:sum(value), avg:avg(value)") }) requests.get('/pages/+aggregate?%s' % qs)
Example response:
HTTP/1.1 200 OK Content-Type: application/json [ { "year": 2019, "month": 1, "day": 1, "sum": 45, "count": 11, "avg": 4.5 }, { "year": 2019, "month": 1, "day": 2, "sum": 60, "count": 14, "avg": 4.6 } ]
- GET /pages/+search¶
The search API allows you to do advanced querying on your resources using Rulez query structure.
- Query Parameters:
select – jsonpath field selector
q –
rulez
dsl based filter queryorder_by – string in
field:order
format whereorder
isasc
orasc
andfield
is the field name.offset – result offset
limit – result limit
Warning
select
query parameter would alter the response data structure from{"data":{},"links":[]}
to["val1","val2","val3" ... ]
Example request:
from urllib.parse import urlencode import json import requests qs = urlencode({ 'q': 'body in ["Hello"]' }) requests.get('http://localhost:5000/pages/+search?%s' % qs)
Example response:
HTTP/1.1 200 OK Content-Type: application/json { "results": [ {"data": {}, "links": []}, {"data": {}, "links": []}, {"data": {}, "links": []}, {"data": {}, "links": []} ], "q": null }
Model¶
- GET /page/{uuid}¶
Display resource data
Example response:
HTTP/1.1 200 OK Content-Type: application/json { "data": { "id": 1, "uuid": "ea31ebb4eb814572b2cbfc2d30fac7f2", "creator": "285969eefd7547d38fb3a5d06996f93e", "created": "2019-01-29T08:37:48.653715", "modified": "2019-01-29T08:37:48.653715", "state": null, "deleted": null, "body": "Hello world", "value": 0 }, "links": [ { "rel": "self", "href": "http://localhost:5000/pages/ea31ebb4eb814572b2cbfc2d30fac7f2" }, { "rel": "update", "href": "http://localhost:5000/pages/ea31ebb4eb814572b2cbfc2d30fac7f2", "method": "PATCH" }, { "rel": "delete", "href": "http://localhost:5000/pages/ea31ebb4eb814572b2cbfc2d30fac7f2", "method": "DELETE" } ] }
- PATCH /page/{uuid}¶
Update resource data
Example request:
PATCH /pages/ea31ebb4eb814572b2cbfc2d30fac7f2 HTTP/1.1 Content-Type: application/json { "body": "Foo bar" }
Example response:
HTTP/1.1 200 OK Content-Type: application/json {"status": "success"}
- DELETE /page/{uuid}¶
Delete resource
Example request:
DELETE /pages/ea31ebb4eb814572b2cbfc2d30fac7f2 HTTP/1.1
Example response:
HTTP/1.1 200 OK Content-Type: application/json {"status": "success"}
- POST /page/{uuid}/+blobs?field={blobfieldname}¶
Upload blob using HTTP file upload
Example request:
import json import requests requests.post('http://localhost:5000/pages/ea31ebb4eb814572b2cbfc2d30fac7f2/+blobs?field=attachment', files={'upload': open('/path/to/file.jpg')})
Example response:
HTTP/1.1 200 OK Content-Type: application/json {"status": "success"}
- GET /page/{uuid}/+blobs?field={blobfieldname}¶
Download blob
- DELETE /page/{uuid}/+blobs?field={blobfieldname}¶
Delete blob
- GET /page/{uuid}/+xattr-schema¶
Get JSON schema for validating extended attributes. This view is only available if your model have an extended attribute provider registered
- GET /page/{uuid}/+xattr¶
Return extended attributes. This view is only available if your model have an extended attribute provider registered
Example response:
HTTP/1.1 200 OK Content-Type: application/json { "field1": "value1", "field2": "value2" }
- PATCH /page/{uuid}/+xattr¶
Update extended attributes. This view is only available if your model have an extended attribute provider registered
Example request:
PATCH /pages/ea31ebb4eb814572b2cbfc2d30fac7f2/+xattr HTTP/1.1 Content-Type: application/json { "field1": "value3", "field3": "value4" }
Example response:
HTTP/1.1 200 OK Content-Type: application/json {"status": "success"}
- POST /pages/{uuid}/+statemachine¶
Apply transition. This view is only available if your model have a state machine registered.
Example request:
POST /pages/ea31ebb4eb814572b2cbfc2d30fac7f2 HTTP/1.1 Content-Type: application/json {"transition": "approve"}
Example response:
HTTP/1.1 200 OK Content-Type: application/json {"status":"success"}