Create api.py for any application which needs an api.
Create yourt methods:
import api
from api.models import Role
@api.method:
def describe_site(rl:Role)->str:
return 'My wonderful site'
These types are allowed:
Nonestrbytesbool intfloatdatetime sent as a float number of seconds since 1 Jan 1971Enumsmodels.Model prepared for use in your API - see here for details. A models.Model configured for API are also known as a resource.@dataclass classesList[]sDict[]sapi.Json for treating dicts & lists as json.api_api.FileUploadapi.pys in your site's applications@api.methodrl:Role as their first parameter@api.methodnamename is not given, the python function's name is used.require_host (None)This allows a check on request.META['HTTP_HOST']. This can be:
str @api.method(require_host='dev.mysite.com')
def describe_local_IP()->str
...
tuple, list or set of str @api.method(require_host=['dev.mysite.com'])
def describe_local_IP()->str
...
require_host(host:str)->boolTrue if the host is allowed, False otherwise@api.method(require_host=[lambda host:host == 'dev.mysite.com'])
def describe_local_IP()->str
...
require_auth (default True)False to allow this method for all callers regardless of what authorisation,
if any, has been provided. When this is False, user_check and read_only_resources are ignored. Use require_auth=False with caution!user_check (default None).user_check(user:UserModel)->bool, which should return True if the user is allowed to call this method. For example, some methods might only be allowed for calls between instances serving your website: user_check = lambda user: return user == home.site_user
read_only_resources (None, all resources are changed)describes which resources in the parameters are read only, ie not changed. This is used for checking a caller's permission. It can be:
str of '0's and '1's'1' means the resource is left unchanged by this method.@api.method(read_only_resources='01')
def modify_user_favourite(user:UserModel, repo:Repo, favourite:bool)->None
...
list, tuple or set of classes@api.method(read_only_resources=[Repo])
def modify_user_favourite(user:UserModel, repo:Repo, favourite:bool)->None
...
read_only_resources(resources:List[resource])->strReturn a str of '0's and '1's. Each '0' and '1' corresponds to a passed-in resource, where '1' means the resource is left unchanged by this method.
@api.method(read_only_resources=lambda resources:'01') def modify_user_favourite(user:UserModel, repo:Repo, favourite:bool)->None ...
resource_access (None, all resources are fully accessed)describe the access to the passed-in resources. Access is classified into public, read
or full. Public is more permissive than read access, for example describe_user might
require read access, as it gives information, such as the user's email address, which
the user might not want public, whereas describe_user_brief might only give the
username, which is generally known.
It can be:
str of 'p's, 'r's or 'f's{str: access}owner is a modified resource, the 'owner': 'f',;
suppose argument fred is a list of resources which are only read, then 'fred[]': 'r',;
suppose betty is a dataclass with resource field owner used publicly, then 'betty.owner': 'p',;
suppose complex is a dictionary with resource keys publically used and resource values modified, then 'complex[key]': 'p', 'complex[]: 'f','.{type: access}prefer_query (())external (True)ignore_resource_policies (False)Policy's should be ignored for this method. The expected use case are the methods which adjust
a resource's Policy list. If a resource has a Policy added which is irrelevant to its Policy-adjusting method
then, if the Policy was followed, the method would become blocked, and so the resource's Policy list would become
stuck. To prevent this, mark these methods ignore_resource_policies=True.Your API can receive file uploads by using the type api_api.FileUpload. Your methods will receive a FileUpload. A FileUpload has these properties:
namefilecontent_typeTo send files, pass FileUploads to the api_api API for your site
At time of writing requests brings the file into memory before sending it, so avoid sending huge files this way.
At time of writing multi-select <input type="files" .. are not supported through api_api - this is a limitation of requests.
[note to author from author:
To fix requests's sending of files to avoid bringing the whole file into memory first:
change urllib3.filepost.encode_multipart_formdata to prepare the body to be a file-like object which returns a stream of bytes. This stream should be the append of a series of bytes and file-like objects - reading from the file-like objects only when the stream needs it.
change requests.models.RequestEncodingMixin._encode_files to set fdata = fp not fdata = fp.read()
]
A decorated method has these properties:
check_permission(role, ...)