Skip to content

Commit

Permalink
add operations support for django ASGI, optimize operations load_mode…
Browse files Browse the repository at this point in the history
…l, add operations Log config, alter async methods in cache, adding Operations docs
  • Loading branch information
voidZXL committed Nov 19, 2024
1 parent 0b104a8 commit 8848bd2
Show file tree
Hide file tree
Showing 47 changed files with 1,309 additions and 411 deletions.
14 changes: 2 additions & 12 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,8 @@ __pycache__/
/docs/build
/tests/server/tmp/*
/tests/server/tmp
/tests/test_7_ops/utilmeta_site/__default_db
/tests/test_7_ops/utilmeta_site/operations_db
/tests/test_7_ops/flask_site/__default_db
/tests/test_7_ops/flask_site/operations_db
/tests/test_7_ops/fastapi_site/__default_db
/tests/test_7_ops/fastapi_site/operations_db
/tests/test_7_ops/django_site/__default_db
/tests/test_7_ops/django_site/operations_db
/tests/test_7_ops/sanic_site/__default_db
/tests/test_7_ops/sanic_site/operations_db
/tests/test_7_ops/tornado_site/__default_db
/tests/test_7_ops/tornado_site/operations_db
__default_db
operations_db
*.sqlite3
db
db_ops
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ if __name__ == '__main__':
service.run()
```

You can create a python file with the above code and run it to check it out.
You can create a Python file with the above code and run it to check it out.

## Quick Start

Expand Down Expand Up @@ -142,7 +142,14 @@ You can connect your APIs by open this link: [https://ops.utilmeta.com/localhost

Click **API** and your will see the generated API document, you can debug your API here
<img src="https://utilmeta.com/assets/image/connect-local-api.png" href="https://ops.utilmeta.com" target="_blank" width="800"/>
With your local API connected, you can use these features

* **Data**: Manage database data (CRUD), in this example, you can add `user` and `article` instance
* **API**: view and debug on auto generated API document
* **Logs**: query realtime request logs, view request and response data, error tracebacks
* **Servers**: view realtime metrics of service resources like servers, databases, caches

> Using other management features requires you to connect a online service with public network address
## Document Guide
We have several introductory case tutorials from easy to complex, covering most usage of the framework. You can read and learn in the following order.

Expand Down
119 changes: 94 additions & 25 deletions README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

<img src="https://utilmeta.com/img/logo-main-gradient.png" style="width: 200px" alt="">

**UtilMeta** 是一个面向服务端应用的渐进式元框架,基于 Python 类型注解标准高效构建声明式接口与 ORM,支持使用主流 Python 框架作为运行时实现或渐进式整合
**UtilMeta** 是一个面向服务端应用的渐进式 Python 后端元框架,基于 Python 类型注解标准高效构建声明式接口与 ORM,支持使用主流 Python 框架作为运行时实现或渐进式整合

* 主页:[https://utilmeta.com/zh/py](https://utilmeta.com/zh/py)
* 代码:<a href="https://github.com/utilmeta/utilmeta-py" target="_blank">https://github.com/utilmeta/utilmeta-py</a>
* 作者:<a href="https://github.com/voidZXL" target="_blank">@voidZXL</a>
* 语言:[![en](https://img.shields.io/badge/lang-English-blue.svg)](https://github.com/utilmeta/utilmeta-py/blob/main/README.md) [![zh](https://img.shields.io/badge/lang-中文-green.svg)](https://github.com/utilmeta/utilmeta-py/blob/main/README.zh.md)

<a href="https://pypi.org/project/utilmeta/" target="_blank">
<img src="https://img.shields.io/pypi/v/utilmeta" alt="">
Expand All @@ -20,17 +25,6 @@
<img src="https://img.shields.io/github/actions/workflow/status/utilmeta/utilmeta-py/test.yaml?branch=main&label=CI" alt="">
</a>

* 主页:[https://utilmeta.com/zh/py](https://utilmeta.com/zh/py)
* 代码:<a href="https://github.com/utilmeta/utilmeta-py" target="_blank">https://github.com/utilmeta/utilmeta-py</a>
* 作者:<a href="https://github.com/voidZXL" target="_blank">@voidZXL</a>
* 语言:[![en](https://img.shields.io/badge/lang-English-blue.svg)](https://github.com/utilmeta/utilmeta-py/blob/main/README.md) [![zh](https://img.shields.io/badge/lang-中文-green.svg)](https://github.com/utilmeta/utilmeta-py/blob/main/README.zh.md)

## 核心特性

* **渐进式元框架**:使用一套标准支持 django, flask, fastapi (starlette), sanic, tornado 等主流 Python 框架作为 HTTP 运行时实现(切换实现只需一个参数),支持从以上框架的现有项目使用 UtilMeta 进行渐进式开发,灵活兼容多种技术栈,支持异步接口
* **声明式接口与 ORM**:快速产出简洁代码,自动根据声明完成请求校验,响应构建与生成 OpenAPI 标准文档,内置高效的声明式 ORM 标准,支持 django 等查询引擎
* **高度可扩展与丰富的插件**:内置一系列可灵活接入的鉴权(session/jwt),跨域处理,重试,请求控制,事务等插件

## 安装

```shell
Expand All @@ -40,10 +34,59 @@ pip install -U utilmeta
!!! note
UtilMeta 需要 Python >= 3.8

## Hello World
## 核心特性

### 声明式 API 与 ORM

你可以使用 UtilMeta 框架的声明式 API 与 ORM 语法轻松构建 RESTful API, 下面是一个来自 [mini_blog/blog/api.py](https://github.com/utilmeta/utilmeta-py/blob/main/examples/mini_blog/blog/api.py) 的示例

```python
from utilmeta.core import api, orm
from .models import User, Article
from django.db import models

class UserSchema(orm.Schema[User]):
username: str
articles_num: int = models.Count('articles')

class ArticleSchema(orm.Schema[Article]):
id: int
author: UserSchema
content: str

class ArticleAPI(api.API):
async def get(self, id: int) -> ArticleSchema:
return await ArticleSchema.ainit(id)
```

我们新建一个名为 `server.py` 的 Python 文件,并在其中写入以下代码
当年请求 `GET /article?id=1` 到 ArticleAPI,API 会返回类似如下的响应

```python
{
"id": 1,
"author": {
"username": "alice",
"articles_num": 3
},
"content": "hello world"
}
```

可以看到它与你在代码中的声明完全一致,UtilMeta 会自动生成优化后的 ORM 查询,并将结果转化为你定义的类型与结构,自动避免 N+1 查询问题,并且会根据你的声明生成对应的 OpenAPI 文档

### 渐进式元框架

UtilMeta 内置了一套标准支持大部分主流 Python 框架作为 HTTP 运行时实现,灵活兼容多种技术栈,支持异步接口

当前支持的框架包括

* **Django** (与 Django REST framework)
* **Flask** (与 APIFlask)
* **FastAPI** (与 Starlette)
* **Sanic**
* **Tornado**

你可以仅用一个参数切换 API 服务的整个底层实现,比如下面的 hello world 示例代码
```python
from utilmeta import UtilMeta
from utilmeta.core import api
Expand All @@ -68,28 +111,47 @@ if __name__ == '__main__':
service.run()
```

!!! note
除了例子中的 `django` 外,你可以选择其他的框架作为 backend,但你需要先安装它们
你可以创建一个 Python 文件写入并运行以上代码试试看

## 运行项目
## 快速开始

我们可以直接运行这个文件来启动 API 服务
你可以通过 clone 仓库并运行其中的示例项目来快速开始
```shell
python server.py
pip install -U utilmeta
git clone https://github.com/utilmeta/utilmeta-py
cd utilmeta-py/examples/mini_blog
meta migrate # 生成数据库
meta run # 或 python server.py
```

当看到如下提示即说明启动成功
```
Running on http://127.0.0.1:8000
Press CTRL+C to quit
| UtilMeta (version) starting service [blog]
| version: 0.1.0
| stage: ● debug
| backend: fastapi (version) | asynchronous
| base url: http://127.0.0.1:8080
```

接着我们可以直接使用浏览器访问 [http://127.0.0.1:8000/api/hello](http://127.0.0.1:8000/api/hello) 来调用 API,可以看到
### 连接你的 API

当我们启动项目时,我们会看到以下的输出
```
world
UtilMeta OperationsAPI loaded at http://127.0.0.1:8080/ops, connect your APIs at https://ops.utilmeta.com
```

说明项目启动成功
说明项目的运维管理 API 成功加载,我们可以直接点击这个连接: [https://ops.utilmeta.com/localhost?local_node=http://127.0.0.1:8080/ops](https://ops.utilmeta.com/localhost?local_node=http://127.0.0.1:8080/ops) 连接到你的 API 服务

点击左侧 **API** 板块即可看到生成的 API 文档
<img src="https://utilmeta.com/assets/image/connect-local-api.png" href="https://ops.utilmeta.com" target="_blank" width="800"/>
本地 API 在连接平台后可以使用以下功能

* **Data**: 数据管理 CRUD,比如在上面的例子中,你可以进入添加 `user``article` 实例
* **API**:查看并调试自动生成的 API 文档
* **Logs**:查询实时请求日志,包括请求和响应的数据,错误调用栈等
* **Servers**:查询服务依赖的资源的实时监控数据,如服务器,数据库,缓存

> 使用其他的功能需要连接有公开访问地址的 API 服务
## 如何阅读本文档

Expand All @@ -108,4 +170,11 @@ world
* [数据查询与 ORM 操作](guide/schema-query):如何使用 Schema 声明式地编写 RESTful 接口所需要的增删改查和 ORM 操作
* [接口与用户鉴权](guide/auth):如何使用 Session, JWT, OAuth 等方式为接口的请求鉴权,获取当前请求用户与简化登录操作
* [配置运行与部署](guide/config-run):如何使用声明式环境变量等特性配置服务的运行设置,启动与部署
* [从现有项目迁移](guide/migration):如何从现有的后端项目中渐进式地接入 UtilMeta 接口或迁移到 UtilMeta
* [从现有项目迁移](guide/migration):如何从现有的后端项目中渐进式地接入 UtilMeta 接口或迁移到 UtilMeta


## 社区

添加作者微信 (voidZXL) 加入开发者群,验证信息 UtilMeta

<img src="https://utilmeta.com/img/wx_voidzxl.jpg" href="https://utilmeta.com/py" target="_blank" alt="drawing" width="200"/>
1 change: 0 additions & 1 deletion docs/en/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# UtilMeta - Quick Guide
<img src="https://utilmeta.com/img/py-intro.png" href="https://utilmeta.com/py" target="_blank" alt="drawing" width="600"/>

**UtilMeta** is a progressive meta-framework for backend applications, which efficiently builds declarative APIs based on the Python type annotation standard, and supports the integration of mainstream Python frameworks as runtime backend

Expand Down
83 changes: 53 additions & 30 deletions docs/zh/guide/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -422,8 +422,35 @@ class APIClient(cli.Client):

### 客户端的表单与文件

* 直接上传文件
* `multipart/form-data`
使用客户端类为请求添加文件的方式有两种

* **直接上传文件**:直接使用单个文件作为请求体,你可以直接把 `utilmeta.core.file.File` 指定为请求体类型
* **使用表单上传文件**:使用 `multipart/form-data` 表单传输文件,除了文件外你还可以传入其他的表单字段

```python
from utilmeta.core import cli, request, api, file
import utype

class APIClient(cli.Client):
class FormData(utype.Schema):
name: str
files: List[file.File]

@api.post
def multipart(self, data: FormData = request.Body): pass
```

在传入文件时,你可以直接使用 File 传递一个本地文件,比如

```python
client.multipart(data={
'name': 'multipart',
'files': [File(open('test.txt', 'r')), File(open('test.png', 'r'))]
})
```

!!! tip
你可以使用 File 的 `filename` 参数传入文件名,会作为 `multipart/form-data` 表单的文件名传递,如果没有指定的话会识别本地文件的文件名


## 调用 `Client`
Expand Down Expand Up @@ -478,49 +505,46 @@ Response [200 OK] "GET /get?a=1&b=2"
{'a': '1', 'b': '2'}
```

### 自定义调用


### Cookies 会话保持

一个常见的需求是客户端提供一个 Session 会话机制,像浏览器一样,能够保存和记忆响应设置的 Cookies 并且在请求中发送
客户端一个常见的需求是提供一个 Session 会话机制,像浏览器一样,能够保存和记忆响应设置的 Cookies 并且在请求中发送,Client 类就内置了这样的机制

当你的请求的响应包含 `Set-Cookie` 响应头时,Client 类就会解析其中的 Cookie 并且存储,在接下来的请求中 Client 类就会携带这些 Cookie 进行请求

#### 通过 `with` 语句隔离会话

如果你希望 Client 类中的会话状态只保持在一部分代码块中,你可以使用 `with` 语句来组织与隔离这些会话,在 `with` 语句退出时,client 中的 Cookie 等会话状态将会被清理


## 使用 `Client` 插件


### `Client` 中的插件机制


和 API 类不同的是,`Client` 中的请求函数不是通过路由分配的,而是通过函数调用直接调用的,这样的情况下,插件事实上只能作用到 **请求函数** 的级别

所以施加给 Client 类的插件会作用到这个 Client 类中所有的请求函数和挂载的子 `Client`



### `Retry` 重试插件


!!! tip
由于 API 与 `Client` 类的请求响应类型是一致的,`Retry` 重试插件不仅可以用在 `Client` 类或请求函数,也可以用在 API 类和 API 函数中

### 自定义 `Client` 插件

`Client` 插件的逻辑很简单,还记得上文的钩子函数吗?`Client` 插件其实就是提供了一系列钩子函数,用于处理请求,处理响应或者处理错误
```python
client = UserClient(
base_url='http://127.0.0.1:8555/api/user',
)
with client:
resp = client.session_login(
username='alice',
password="******",
)
with client:
resp = client.jwt_login(
username='alice',
password="******",
)
```


## 生成 `Client` 类代码

### 为 UtilMeta 服务生成请求代码

为 UtilMeta 服务自动生成 Client 类的请求 SDK 代码只需要一个命令,在你的项目目录(包含 `meta.ini` 的目录)下执行整个命令

### 为 OpenAPI 文档生成请求代码
```
meta gen_client
```

### 为 OpenAPI 文档生成请求代码

你可以在使用 `meta gen_client` 命令时传入 `--openapi` 参数,指定 OpenAPI 的 URL 或文件地址,UtilMeta 就会根据这个地址对应的 OpenAPI 文档生成客户端请求 SDK 代码

## `Client` 类代码示例

Expand Down Expand Up @@ -589,4 +613,3 @@ class APIClient(cli.Client):
ArticleResponse [200 OK] "GET /api/articles/how-to-train-your-dragon"
```

### OpenAI 对话接口
2 changes: 2 additions & 0 deletions docs/zh/guide/cmd.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ meta init
## 运行与部署


接下来的版本中 UtilMeta 将会提供自动化部署命令,能够自动生成并更新 uwsgi, gunicorn, nginx 等配置文件,以及注册与管理 systemd 服务

## 文档与客户端代码生成

### 生成 OpenAPI 文档
Expand Down
Loading

0 comments on commit 8848bd2

Please sign in to comment.