telepact-api

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Introduction

简介

Telepact is an API ecosystem for bridging programs across inter-process communication boundaries.
What makes Telepact different? It takes the differentiating features of the industry's most popular API technologies, and combines them together through 3 key innovations:
  1. JSON as a Query Language - API calls and
    SELECT
    -style queries are all achieved with JSON abstractions, giving first-class status to clients wielding only a JSON library
  2. Binary without code generation - Binary protocols are established through runtime handshakes, rather than build-time code generation, offering binary efficiency to clients that want to avoid code generation toolchains
  3. Hypermedia without HTTP - API calls can return functions with pre-filled arguments, approximating a link that can be followed, all achieved with pure JSON abstractions
For further reading, see Motivation.
For explanations of various design decisions, see the FAQ.
Telepact是一个用于跨进程通信边界连接程序的API生态系统。
Telepact的独特之处在哪里?它吸纳了行业内最受欢迎的API技术的差异化特性,并通过3项核心创新将它们融合在一起:
  1. JSON作为查询语言 - API调用和类
    SELECT
    查询均通过JSON抽象实现,让仅拥有JSON库的客户端获得一等公民地位
  2. 无需代码生成的二进制支持 - 二进制协议通过运行时握手建立,而非构建时代码生成,为希望避开代码生成工具链的客户端提供二进制效率
  3. 无需HTTP的超媒体 - API调用可返回预填充参数的函数,近似可跟随的链接,所有这些都通过纯JSON抽象实现
如需进一步了解,请参阅动机
如需了解各类设计决策的说明,请参阅常见问题

Explore

探索

To learn how to write Telepact APIs, see the API Schema Guide. A JSON Schema is available for validation.
To learn how to serve a Telepact API, see the specific library docs:
  • Typescript
  • Python
  • Java
  • Go
For development assistance, see the SDK tool docs:
  • CLI
  • Browser Console
  • Prettier Plugin
如需学习如何编写Telepact API,请参阅API Schema指南。我们还提供了JSON Schema用于验证。
如需学习如何部署Telepact API,请参阅特定语言的库文档:
  • Typescript
  • Python
  • Java
  • Go
如需开发辅助工具相关内容,请参阅SDK工具文档:
  • CLI
  • 浏览器控制台
  • Prettier插件

At a glance

概览

Specify your API:
sh
$ cat ./api/math.telepact.json
json
[
    {
        "///": " Divide two integers, `x` and `y`. ",
        "fn.divide": {
            "x": "integer",
            "y": "integer"
        },
        "->": [
            {
                "Ok_": {
                    "result": "number"
                }
            },
            {
                "ErrorCannotDivideByZero": {}
            }
        ]
    }
]
Serve it with one of the Telepact libraries over a transport of your choice:
sh
$ cat ./server.py
py
from telepact import TelepactSchemaFiles, TelepactSchema, Server, Message
from starlette.applications import Starlette
from starlette.responses import Response
from starlette.routing import Route
from starlette.middleware import Middleware
from starlette.middleware.cors import CORSMiddleware
import uvicorn

async def handler(req_msg):
    fn = req_msg.get_body_target()
    args = req_msg.body[fn]
    if fn == 'fn.divide':
        x = args['x']
        y = args['y']
        if y == 0:
            return Message({}, {'ErrorCannotDivideByZero': {}})

        result = x / y
        return Message({}, {'Ok_': {'result': result}})
    else:
        raise Exception('Unknown function')

options = Server.Options()
options.auth_required = False

schema_files = TelepactSchemaFiles('./api')
api = TelepactSchema.from_file_json_map(schema_files.filenames_to_json)
server = Server(api, handler, options)

async def http_handler(request):
    request_bytes = await request.body()
    response = await server.process(request_bytes)
    response_bytes = response.bytes
    media_type = 'application/octet-stream' if 'bin_' in response.headers else 'application/json'
    return Response(content=response_bytes, media_type=media_type)

routes = [
    Route('/api/telepact', endpoint=http_handler, methods=['POST']),
]

middleware = [
    Middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
]

app = Starlette(routes=routes, middleware=middleware)

uvicorn.run(app, host='0.0.0.0', port=8000)
sh
$ poetry add uvicorn starlette telepact
$ poetry run python ./server.py
Then tell your clients about your transport, and they can consume your API with minimal tooling:
$ cat ./client.js
js
let header = {};
let body = {
    "fn.divide": {
        x: 6,
        y: 3,
    }
};
let request = [header, body];
let response = await fetch(
    "http://localhost:8000/api/telepact",
    {
        method: "POST",
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(request),
    },
);
console.log(`Response: ${JSON.stringify(await response.json())}`);
sh
$ node ./client.js
Response: [{},{"Ok_":{"result":2}}]
Or clients can also leverage telepact tooling to:
  • Select less fields to reduce response sizes
  • Generate code to increase type safety
  • Use binary serialization to reduce request/response sizes
定义你的API:
sh
$ cat ./api/math.telepact.json
json
[
    {
        "///": " Divide two integers, `x` and `y`. ",
        "fn.divide": {
            "x": "integer",
            "y": "integer"
        },
        "->": [
            {
                "Ok_": {
                    "result": "number"
                }
            },
            {
                "ErrorCannotDivideByZero": {}
            }
        ]
    }
]
使用任意Telepact库,通过你选择的传输方式部署API:
sh
$ cat ./server.py
py
from telepact import TelepactSchemaFiles, TelepactSchema, Server, Message
from starlette.applications import Starlette
from starlette.responses import Response
from starlette.routing import Route
from starlette.middleware import Middleware
from starlette.middleware.cors import CORSMiddleware
import uvicorn

async def handler(req_msg):
    fn = req_msg.get_body_target()
    args = req_msg.body[fn]
    if fn == 'fn.divide':
        x = args['x']
        y = args['y']
        if y == 0:
            return Message({}, {'ErrorCannotDivideByZero': {}})

        result = x / y
        return Message({}, {'Ok_': {'result': result}})
    else:
        raise Exception('Unknown function')

options = Server.Options()
options.auth_required = False

schema_files = TelepactSchemaFiles('./api')
api = TelepactSchema.from_file_json_map(schema_files.filenames_to_json)
server = Server(api, handler, options)

async def http_handler(request):
    request_bytes = await request.body()
    response = await server.process(request_bytes)
    response_bytes = response.bytes
    media_type = 'application/octet-stream' if 'bin_' in response.headers else 'application/json'
    return Response(content=response_bytes, media_type=media_type)

routes = [
    Route('/api/telepact', endpoint=http_handler, methods=['POST']),
]

middleware = [
    Middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
]

app = Starlette(routes=routes, middleware=middleware)

uvicorn.run(app, host='0.0.0.0', port=8000)
sh
$ poetry add uvicorn starlette telepact
$ poetry run python ./server.py
然后告知客户端你的传输方式,他们即可用最少的工具调用你的API:
$ cat ./client.js
js
let header = {};
let body = {
    "fn.divide": {
        x: 6,
        y: 3,
    }
};
let request = [header, body];
let response = await fetch(
    "http://localhost:8000/api/telepact",
    {
        method: "POST",
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(request),
    },
);
console.log(`Response: ${JSON.stringify(await response.json())}`);
sh
$ node ./client.js
Response: [{},{"Ok_":{"result":2}}]
客户端还可以利用Telepact工具实现以下功能:
  • 选择更少字段以减小响应体积
  • 生成代码以提升类型安全性
  • 使用二进制序列化以减小请求/响应体积

Licensing

许可证

Telepact is licensed under the Apache License, Version 2.0. See LICENSE for the full license text. See NOTICE for additional information regarding copyright ownership.
Telepact采用Apache License, Version 2.0许可证。请参阅LICENSE获取完整许可证文本。请参阅NOTICE了解有关版权归属的额外信息。