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:
- 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 - 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
- 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.
For how-to guides, see the API Schema Guide, as well as the library and SDK docs:
Specify your API:
$ cat ./api/math.telepact.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:
$ cat ./server.pyfrom 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)$ poetry add uvicorn starlette telepact
$ poetry run python ./server.pyThen tell your clients about your transport, and they can consume your API with minimal tooling:
$ cat ./client.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())}`);$ 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
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.