Package: aurelix
Aurelix: Low Code API Framework Based on FastAPI, Dectate and SQLAlchemyAurelix is a low code framework for quickly building APIs for storing data and files. It is built on top of FastAPI and SQLAlchemy, and inherit some extension capabilities from Morepath's Dectate library, and pretty much a rewrite of all core ideas from MorpFW into a new framework to address deficiency and problems of the original implementation.Aurelix uses YAML for define composable data models in declarative manner and interprets it into RESTful API that follows a degree of JSONAPI specification.Capabilities definable through the YAML includes:Data structure - You can define fields which will be interpreted as table columns.Built-in CRUD views - Save time writing RESTful CRUD views as Aurelix includes the usualGET,PUT,PATCH,DELETEoperations, alongside a search URL with pagination.Custom views - Extend your app and model with custom views of your own, you can either reference to a function in a module, or you can just put the code in the YAML.OIDC integration - If you are using OIDC provider that provides OIDC
discoverability endpoint, you can use that OIDC provider for authentication.Collection-wide permission filtering - You can specify role-specificwherefilters which will be applied to different roles to allow or prevent them from seeing specific sections of you dataField permission filtering - You can specify role specific field permissions to limit access to fields (readWrite,readOnly,restricted) by role.Field transformation chain - You can specify input and output transformation chain for fields, for example, to encrypt and decrypt data before storing into database.Model transformation chain - Similar as field transformation chain, but this applies against the whole record.Field validation chain - Register custom functions to validate field values when create/update.Object storage integration - Use string field as object storage referencing field, which integrates with S3/MinIO based object storage for upload and download through presigned URLs.State machine - Define state machine workflow chain for your model for state tracking, including custom functions to trigger on state change.Event hooks - Register functions to be triggered oncreate,updateanddeleterelated events.Additionally, if you are a data engineer and need to have good management of your data model version and migration, Aurelix uses Alembic integration manage versioning of your data model.Aurelix also have its own client library which helps interacting with the API server easily, which you can use for writing code-generating ETLs or whatever integration processes.InstallingAurelix requires Python 3.11+Install full server$pipinstallaurelix[server]Only install for client library use$pipinstallaurelixInitializing applicationTo initialize and application, you can run$aurelixinitmyprojectAnd start it using$cdmyproject/$alembicrevision--autogenerate-m"initial model"$alembicupgradehead$exportAURELIX_CONFIG=`pwd`/app.yaml$aurelixrunExample appThis example shows a bit more of Aurelix capabilities. Detailed documentation is still WIP.Project directory of this sample app looks like this:myproject/
`- app.yaml
`- models/
 `- mymodel.yaml
`- libs/
 `- myviews.pyContents ofapp.yaml:spec_version:app/0.1title:MyAppdatabases:-name:defaulturl:sqlite:///./database.sqliteContents oflibs/myviews.py. Aurelix config can load views and modules fromlibs/directory:fromfastapiimportRequestasyncdefmyview(request:Request):return{'hello':'world'}Contents ofmodels/mymodel.yaml. Automated API creation from model is where the bulk of Aurelix features are:spec_version:model/0.1name:mymodelstorageType:name:sqlalchemydatabase:defaultfields:title:title:TitledataType:type:stringsize:128required:trueworkflowStatus:title:Workflow StatusdataType:type:stringsize:64required:trueindexed:trueviews:extensions:-'/+custom-view':method:GEThandler:function:myviews:myviewtags:-custom tagStart up the service:Using docker$dockerrun-v/path/to/myproject:/opt/app-p8000:8000-ti--rmdocker.io/kagesenshi/aurelix:latestUsingaurelixcommand$exportAURELIX_CONFIG='/path/to/myproject/app.yaml'$aurelixrun-l0.0.0.0Configuration SpecAurelix works around YAML configuration for composing your application and models. This allows decoupling between the framework and the apps and also can pave the way for further automation in YAML generation.App Configurationapp.yamldefines metadata about the application, which includes the FastAPI's app metadata (app title, summary, toc, swagger UI init oauth config), list of databases the application will connect to, and list of view functions to be registered at the root of the app. Following example shows some of the options can be defined onapp.yamlspec_version:app/0.1title:Applicationsummary:My sample appversion:0.1.0terms_of_service:model_directory:models# directory to model YAML spec, relative to app.yamllibs_directory:libs# directory to libs directory, relative to app.yamldatabases:# sqlalchemy database connections to create for the app-name:defaulttype:sqlalchemyurl:sqlite:///./database.sqlite# url_env: DB_URL # environment variable that stores the database urlobject_stores:-name:defaulttype:minio# type of object storage, we only support MinIO or MinIO compatible servers for now.endpoint_url:http://localhost:9000# endpoint_url_env: S3_ENDPOINT # environment variable that stores endpoint urlaccess_key:accesskey# object storage access keysecret_key:secretkey# object storage secret key# access_key_env: S3_ACCESS_KEY # environment variable that stores the access key# secret_key_env: S3_SECRET_KEY # environment variable that stores the secret keyswagger_ui_init_oauth:# set this if you want to enable swagger UI OIDC authclient_id:# oidc client ID for swagger UIclient_secret:# oidc client secret for swagger UIoidc_discovery_endpoint:# url to .well-known/openid-configuration of OIDC provider to use as external token providerviews:extensions:# view registry on the root of the app. use this place add views on your app that is not attached to a model'/+hello':method:'GET'handler:code:|def function(request: Request):return {'message': 'boo'}For more details aboutapp.yamlspec, checkoutAppSpecinconfiguration options.Model ConfigurationModel configuration is where the bulk of Aurelix capability is, as Aurelix generates API on top of data model specification.name:mymodel# name of the model, this translates to database table name for sqlalchemy storagestorage_type:name:sqlalchemy# type of storage to use, for now we only have sqlalchemydatabase:default# name of storagefields:# this contain the list of fields you want to have in your model.title:title:Titledata_type:type:stringsize:128required:truedefault:nullindexed:falseunique:falsevalidators:# validator chain-code:|from aurelix import excdef function(collection, value, data):# collection: refers to collection object# value: value of the field to validate# data: refers to full model data to validateif not value.startswith('prefix'):raise exc.ValidationError("Invalid title")-function:mypackage.mymodule:myfunction# you can also specify reference to function in python moduleencodedString:# you can transform field value before storing into db and when loading from dbtitle:Encoded stringdata_type:type:stringsize:128required:falsedefault:nullindexed:falseunique:falseinput_transformers:# input serialization transform chain before storing in database-code:|import base64def function(collection, value, data):return base64.b64encode(value.encode('utf8')).decode('utf8')output_transformers:# output deserialization transform chain before returning to user-code:|import base64def function(collection, value, data):return base64.b64decode(value.encode('utf8')).decode('utf8')selectionField:# you can also specify enum fieldstitle:Selection fielddataType:type:stringsize:128enum:-value:option1label:Option 1 Title-value:option2label:Option 2 TitlefileUpload:# you can create a string field for referencing to object storage data. refer to objectStore option on the model level belowtitle:File Uploaddata_type:type:stringsize:128objectStore:# this contains objectStore settings for each fieldfileUpload:type:minio# type of object storage, we only support MinIO or MinIO compatible servers for now.endpoint_url:http://localhost:9000bucket:mybucketaccess_key_env:S3_ACCESS_KEY# environment variable that stores the access keysecret_key_env:S3_SECRET_KEY# environment variable that stores the secret keyvalidators:# validation chain on the model itself-code:|from aurelix import excdef function(collection, data):# collection: refers to collection object# data: refers to full model data to validatepassdefault_field_permission:readWrite# default permission to all fieldspermission_filters:# permission filtering rules. it is evaluated from top to bottom# row filtering by roles-identities:-'role:mygroup'where_filter:title like '%postfix'# use SQL where statement here for sqlalchemy storage-identities:-'*'# all identitieswhere_filter:0=1# column filtering by roles-identities:-'role:group1'default_field_permission:restrictedread_write_fields:-titleread_only_fields:-fileUpload-identities:-'role:group2'default_field_permission:readWriterestricted_fields:-title-identities:-'*'default_field_permission:restrictedviews:# views registry for the modellisting:enabled:truemax_page_size:100create:enabled:trueread:enabled:trueupdate:enabled:truedelete:enabled:trueextensions:# custom views registry. views registered here is relative to the collection'/+hello':method:'GET'handler:code:|# you can use fastapi dependency injection heredef function(request: Request, collection: Collection):return {'message': 'collection view'}'/{identifier}/+hello':# this view is attached to modelmethod:'GET'handler:code:|# you can use fastapi dependency injection heredef function(request: Request, collection: Collection, model: Model):return {'message': 'model view'}tags:-mytag# openapi tag to group all views asstateMachine:# if you want statemachine on +transition view, configure it here. it uses pytransition internally.initial_state:newfield:workflowStatusstates:-value:newlabel:New-value:runninglabel:Processing-value:completedlabel:Completed-value:failedlabel:Failedon_enter:# you can trigger functions on state enter/exitcode:|from aurelix.crud.base import StateMachinedef function(sm: StateMachine):request = sm.requestitem = sm.item# do something hereon_exit:code:|from aurelix.crud.base import StateMachinedef function(sm: StateMachine):request = sm.requestitem = sm.item# do something here-value:terminatedlabel:Cancelledtransitions:-trigger:startlabel:Startsource:newdest:running-trigger:stoplabel:Stopsource:runningdest:terminated-trigger:completelabel:Mark as completedsource:runningdest:completed-trigger:faillabel:Mark as failedsource:runnningdest:failedbefore_create:-code:|def function(collection, data: dict):# do something herepassafter_create:-code:|def function(collection, item: Model):# do something herepassbefore_update:-code:|def function(collection, data: dict):# do something herepassafter_update:-code:|def function(collection, item: Model):# do something herepassbefore_delete:-code:|def function(collection, item: Model):# do something herepassafter_delete:-code:|def function(collection, data: dict):# do something herepasstransform_create_data:-code:|def function(collection, data: dict):# do something herereturn datatransform_update_data:-code:|def function(collection, data: dict):# do something herereturn datatransform_output_data:-code:|def function(collection, data: dict):# do something herereturn dataFor more details about model spec formymodel.yaml, check outModelSpecinconfiguration optionsClient LibraryAurelix includes client library for interacting Aurelix serverfromaurelix.clientimportClientaurelix=Client('http://localhost:8000')# create objectitem=aurelix['mymodel'].create({'title':'Title 1'})# update objectitem.update({'title':'Title 2'})# delete objectitem.delete()CommunityCome join us at athttps://discord.gg/yuutKdDChangelog for Aurelix0.1.2b8 (2023-10-20)Added json field support0.1.2b7 (2023-10-16)Added non-async sqlalchemy storage type (sqlalchemy-sync).MSSQL users must use the non-async storage type0.1.2b6 (2023-09-02)Added missing manifest inclusion for yaml based init templates0.1.2b5 (2023-08-27)Use snake case in configurationAdded simple unit tests0.1.2b4 (2023-08-26)validate & decode oidc token instead of blindly trusting it by querying userinfo endpointremove UserInfo class as a decoded token have sufficient identity informationadded relationships object in model responsesadded relationship traversal in client0.1.2b3 (2023-08-24)added object storage support for object uploadsadded field editing guard for object storage fields and workflow fields0.1.2b2 (2023-08-23)Added hooks for field and model validationallow specifying function name in CodeRefSpecadded field input/output transfomer hooksadded alembic support0.1.2.beta1 (2023-08-22)fixed after/before create/update/delete event hooks not triggeringfixed transform create/update/output transform hooks not overriding correctlyevent hooks and transform hooks are now multi-item and chainablefix MANIFEST.in that caused failure to install from pip0.1.1 (2023-08-21)added field level permission filteradded encrypted-string fieldexclude null from response objectsfixed startup issue whenswagger_ui_init_oauthnot configuredaddedinitcli command to initialize project0.1 (2023-08-21)initial release