跳转到主要内容

基于Dectate和FastAPI的低代码API框架

项目描述

Aurelix:基于FastAPI、Dectate和SQLAlchemy的低代码API框架

Aurelix是一个用于快速构建用于存储数据和文件API的低代码框架。它建立在FastAPI和SQLAlchemy之上,并从Morepath的Dectate库中继承了一些扩展功能,基本上是将MorpFW的所有核心思想重写到一个新的框架中,以解决原始实现中的缺陷和问题。

Aurelix使用YAML以声明方式定义可组合的数据模型,并将其解释为遵循一定程度JSONAPI规范的RESTful API。

通过YAML可定义的能力包括

  • 数据结构 - 您可以定义字段,这些字段将被解释为表列。
  • 内置CRUD视图 - 通过Aurelix包含的常用GETPUTPATCHDELETE操作以及带有分页的搜索URL来节省编写RESTful CRUD视图的时间。
  • 自定义视图 - 通过自定义视图扩展您的应用程序和模型,您可以引用模块中的函数,或者只需在YAML中放置代码。
  • OIDC集成 - 如果您正在使用提供OIDC发现端点的OIDC提供程序,您可以使用该OIDC提供程序进行身份验证。
  • 集合范围权限过滤 - 您可以指定特定角色的where过滤器,该过滤器将应用于不同角色,以允许或阻止它们查看您数据的具体部分。
  • 字段权限过滤 - 您可以指定特定角色的字段权限,以限制按角色访问字段(readWritereadOnlyrestricted)。
  • 字段转换链 - 您可以指定字段输入和输出转换链,例如,在存储到数据库之前加密和解密数据。
  • 模型转换链 - 与字段转换链类似,但这是针对整个记录的应用。
  • 字段验证链 - 在创建/更新时注册自定义函数以验证字段值。
  • 对象存储集成 - 使用字符串字段作为对象存储引用字段,与基于S3/MinIO的对象存储集成,通过预签名URL进行上传和下载。
  • 状态机 - 为您的模型定义状态机工作流程链以跟踪状态,包括在状态更改时触发的自定义函数。
  • 事件钩子 - 将函数注册到 createupdatedelete 相关事件上。

此外,如果您是数据工程师并且需要良好地管理数据模型版本和迁移,Aurelix 使用 Alembic 集成来管理数据模型的版本。

Aurelix 还拥有自己的客户端库,它可以帮助您轻松地与 API 服务器交互,您可以使用它来编写代码生成 ETL 或其他集成过程。

安装

Aurelix 需要 Python 3.11+

安装完整服务器

$ pip install aurelix[server]

仅安装客户端库使用

$ pip install aurelix

初始化应用程序

要初始化应用程序,您可以运行

$ aurelix init myproject

然后使用以下命令启动它

$ cd myproject/
$ alembic revision --autogenerate -m "initial model"
$ alembic upgrade head
$ export AURELIX_CONFIG=`pwd`/app.yaml
$ aurelix run 

示例应用程序

此示例展示了 Aurelix 的一些功能。详细文档仍在进行中。

此示例应用程序的项目目录如下所示

myproject/
`- app.yaml
`- models/
 `- mymodel.yaml
`- libs/
 `- myviews.py

app.yaml 的内容

spec_version: app/0.1
title: MyApp
databases:
  - name: default
    url: sqlite:///./database.sqlite

libs/myviews.py 的内容。Aurelix 配置可以从 libs/ 目录加载视图和模块

from fastapi import Request

async def myview(request: Request):
    return {
       'hello': 'world'
    }

models/mymodel.yaml 的内容。从模型自动创建 API 是 Aurelix 功能的核心

spec_version: model/0.1
name: mymodel
storageType:
  name: sqlalchemy
  database: default
fields:
  title:
    title: Title
    dataType:
      type: string
      size: 128
    required: true

  workflowStatus:
    title: Workflow Status
    dataType:
      type: string
      size: 64
    required: true
    indexed: true

views:
  extensions:
    - '/+custom-view':
        method: GET
        handler:
          function: myviews:myview
          
tags:
  - custom tag

启动服务

使用 Docker

$ docker run -v /path/to/myproject:/opt/app -p 8000:8000 -ti --rm docker.io/kagesenshi/aurelix:latest

使用 aurelix 命令

$ export AURELIX_CONFIG='/path/to/myproject/app.yaml'
$ aurelix run -l 0.0.0.0

配置规范

Aurelix 通过 YAML 配置来组合应用程序和模型。这允许框架和应用程序之间的解耦,并为 YAML 生成自动化铺平道路。

应用程序配置

app.yaml 定义了有关应用程序的元数据,包括 FastAPI 的应用程序元数据(应用程序标题、摘要、目录、swagger UI 初始化 oauth 配置)、应用程序将连接到的数据库列表以及要在应用程序根处注册的视图函数列表。以下示例展示了可以在 app.yaml 上定义的一些选项

spec_version: app/0.1
title: Application
summary: My sample app
version: 0.1.0
terms_of_service: 
model_directory: models # directory to model YAML spec, relative to app.yaml
libs_directory: libs # directory to libs directory, relative to app.yaml
databases: # sqlalchemy database connections to create for the app
  - name: default 
    type: sqlalchemy
    url: sqlite:///./database.sqlite
    # url_env: DB_URL # environment variable that stores the database url
object_stores:
  - name: default
    type: 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 url
    access_key: accesskey # object storage access key
    secret_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 key


swagger_ui_init_oauth: # set this if you want to enable swagger UI OIDC auth
  client_id: # oidc client ID for swagger UI
  client_secret: # oidc client secret for swagger UI
oidc_discovery_endpoint: # url to .well-known/openid-configuration of OIDC provider to use as external token provider
views: 
  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'}

有关 app.yaml 规范的更多详细信息,请参阅 配置选项 中的 AppSpec

模型配置

模型配置是 Aurelix 功能的核心,因为 Aurelix 在数据模型规范之上生成 API。

name: mymodel # name of the model, this translates to database table name for sqlalchemy storage
storage_type:
  name: sqlalchemy # type of storage to use, for now we only have sqlalchemy
  database: default # name of storage
fields: # this contain the list of fields you want to have in your model. 
  title:
    title: Title 
    data_type:
      type: string
      size: 128
    required: true
    default: null
    indexed: false
    unique: false
    validators: # validator chain
      - code: |
          from aurelix import exc

          def function(collection, value, data):
              # collection: refers to collection object
              # value: value of the field to validate
              # data: refers to full model data to validate
              if not value.startswith('prefix'):
                 raise exc.ValidationError("Invalid title")
      - function: mypackage.mymodule:myfunction # you can also specify reference to function in python module
  encodedString: # you can transform field value before storing into db and when loading from db
    title: Encoded string 
    data_type:
      type: string
      size: 128
    required: false
    default: null
    indexed: false
    unique: false
    input_transformers: # input serialization transform chain before storing in database
      - code: |
          import base64
          def function(collection, value, data):
              return base64.b64encode(value.encode('utf8')).decode('utf8')
    output_transformers: # output deserialization transform chain before returning to user
      - code: |
          import base64
          def function(collection, value, data):
              return base64.b64decode(value.encode('utf8')).decode('utf8')
  selectionField: # you can also specify enum fields
    title: Selection field
    dataType:
      type: string
      size: 128
      enum: 
        - value: option1
          label: Option 1 Title
        - value: option2
          label: Option 2 Title
  fileUpload:  # you can create a string field for referencing to object storage data. refer to objectStore option on the model level below
    title: File Upload
    data_type:
      type: string
      size: 128
objectStore:  # this contains objectStore settings for each field
  fileUpload: 
    type: minio # type of object storage, we only support MinIO or MinIO compatible servers for now.
    endpoint_url: http://localhost:9000 
    bucket: mybucket 
    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 key

validators: # validation chain on the model itself
  - code: |
      from aurelix import exc
      
      def function(collection, data):
          # collection: refers to collection object
          # data: refers to full model data to validate
          pass

default_field_permission: readWrite # default permission to all fields
permission_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 identities
    where_filter: 0=1 

  # column filtering by roles
  - identities:
      - 'role:group1'
    default_field_permission: restricted
    read_write_fields:
      - title
    read_only_fields:
      - fileUpload
  - identities:
      - 'role:group2'
    default_field_permission: readWrite
    restricted_fields:
      - title
  - identities:
      - '*'
    default_field_permission: restricted

views: # views registry for the model
  listing:
    enabled: true
    max_page_size: 100
  create:
    enabled: true
  read:
    enabled: true
  update:
    enabled: true
  delete:
    enabled: true
  extensions: # custom views registry. views registered here is relative to the collection
    '/+hello':
      method: 'GET'
      handler:
        code: | # you can use fastapi dependency injection here
          def function(request: Request, collection: Collection):
              return {'message': 'collection view'}
    '/{identifier}/+hello': # this view is attached to model
      method: 'GET'
      handler:
        code: | # you can use fastapi dependency injection here
          def function(request: Request, collection: Collection, model: Model):
              return {'message': 'model view'}
tags: 
  - mytag # openapi tag to group all views as
stateMachine: # if you want statemachine on +transition view, configure it here. it uses pytransition internally.
  initial_state: new
  field: workflowStatus
  states:
    - value: new
      label: New
    - value: running
      label: Processing
    - value: completed
      label: Completed
    - value: failed
      label: Failed 
      on_enter: # you can trigger functions on state enter/exit
        code: |
          from aurelix.crud.base import StateMachine

          def function(sm: StateMachine):
              request = sm.request
              item = sm.item
              # do something here
      on_exit: 
        code: |
          from aurelix.crud.base import StateMachine

          def function(sm: StateMachine):
              request = sm.request
              item = sm.item              
              # do something here
    - value: terminated
      label: Cancelled
  transitions:
    - trigger: start
      label: Start
      source: new
      dest: running
    - trigger: stop
      label: Stop
      source: running
      dest: terminated
    - trigger: complete
      label: Mark as completed
      source: running
      dest: completed
    - trigger: fail
      label: Mark as failed
      source: runnning
      dest: failed

before_create: 
  - code: |
      def function(collection, data: dict):
          # do something here
          pass
after_create: 
  - code: |
      def function(collection, item: Model):
          # do something here
          pass
before_update: 
  - code: |
      def function(collection, data: dict):
          # do something here
          pass
after_update: 
  - code: |
      def function(collection, item: Model):
          # do something here
          pass
before_delete: 
  - code: |
      def function(collection, item: Model):
          # do something here
          pass
after_delete: 
  - code: |
      def function(collection, data: dict):
          # do something here
          pass

transform_create_data: 
  - code: |
      def function(collection, data: dict):
          # do something here
          return data
  
transform_update_data: 
  - code: |
      def function(collection, data: dict):
          # do something here
          return data
transform_output_data: 
  - code: |
      def function(collection, data: dict):
          # do something here
          return data

有关 mymodel.yaml 的模型规范的更多详细信息,请参阅 配置选项 中的 ModelSpec

客户端库

Aurelix 包括用于与 Aurelix 服务器交互的客户端库

from aurelix.client import Client

aurelix = Client('http://localhost:8000')

# create object

item = aurelix['mymodel'].create({'title': 'Title 1'})

# update object
item.update({'title': 'Title 2'})

# delete object
item.delete()

社区

加入我们吧:https://discord.gg/yuutKdD

Aurelix 的变更日志

0.1.2b8 (2023-10-20)

  • 添加了 json 字段支持

0.1.2b7 (2023-10-16)

  • 添加了非异步 sqlalchemy 存储类型(sqlalchemy-sync)。
  • MSSQL 用户必须使用非异步存储类型

0.1.2b6 (2023-09-02)

  • 添加了基于 yaml 的初始化模板中缺失的清单包含

0.1.2b5 (2023-08-27)

  • 在配置中使用蛇形命名法
  • 添加了简单的单元测试

0.1.2b4 (2023-08-26)

  • 通过查询 userinfo 端点验证并解码 oidc 令牌,而不是盲目地信任它
  • 删除 UserInfo 类,因为解码的令牌包含足够的身份信息
  • 在模型响应中添加了关系对象
  • 在客户端中添加了关系遍历

0.1.2b3 (2023-08-24)

  • 添加了对对象上传的对象存储支持
  • 添加了对象存储字段和工作流字段的字段编辑保护

0.1.2b2 (2023-08-23)

  • 添加了字段和模型验证的钩子
  • 允许在 CodeRefSpec 中指定函数名
  • 添加了字段输入/输出转换钩子
  • 添加了 alembic 支持

0.1.2.beta1 (2023-08-22)

  • 修复了在 create/update/delete 事件中事件钩子未触发的问题
  • 修复了 transform create/update/output 转换钩子未正确覆盖的问题
  • 事件钩子和转换钩子现在是多项目和可链接的
  • 修复了导致从 pip 安装失败的 MANIFEST.in

0.1.1 (2023-08-21)

  • 添加了字段级别权限筛选器
  • 添加了加密字符串字段
  • 从响应对象中排除空值
  • 修复了当未配置 swagger_ui_init_oauth 时的启动问题
  • 添加了 init 命令行工具来初始化项目

0.1 (2023-08-21)

  • 首次发布

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪一个,请了解有关 安装包 的更多信息。

源代码分发

aurelix-0.1.2b8.tar.gz (45.7 kB 查看哈希值)

上传时间 源代码

支持