Python implementation of AT Protocol's XRPC + Lexicon
Project description
lexrpc
Python implementation of AT Protocol's XRPC + Lexicon. lexrpc includes a simple XRPC client, server, and Flask web server integration. All three include full Lexicon support for validating inputs, outputs, and parameters against their schemas.
Install from PyPI with pip install lexrpc
or pip install lexrpc[flask]
.
License: This project is placed in the public domain.
Client
The lexrpc client let you call methods dynamically by their NSIDs. To make a call, first instantiate a Client
object with the server address and method lexicons, then use method NSIDs to make calls, passing input as a dict and parameters as kwargs:
from lexrpc import Client
lexicons = [...]
client = Client('https://xrpc.example.com', lexicons)
output = client.com.example.my_query({'foo': 'bar'}, param_a=5)
Note that -
characters in method NSIDs are converted to _
s, eg the call above is for the method com.example.my-query
.
Server
To implement an XRPC server, use the Server
class. It validates parameters, inputs, and outputs. Use the method
decorator to register method handlers and call
to call them, whether from your web framework or anywhere else.
from lexrpc import Server
lexicons = [...]
server = Server(lexicons)
@server.method('com.example.my-query')
def my_query_hander(input, **params):
output = {'foo': input['foo'], 'b': params['param_a'] + 1}
return output
# Extract nsid and decode query parameters from an HTTP request,
# call the method, return the output in an HTTP response
nsid = request.path.removeprefix('/xrpc/')
input = request.json()
params = server.decode_params(nsid, request.query_params())
output = server.call(nsid, input, **params)
response.write_json(output)
Flask server
To serve XRPC methods in a Flask web app, first install the lexrpc package with the flask
extra, eg pip install lexrpc[flask]
. Then, instantiate a Server
and register method handlers as described above. Finally, attach the server to your Flask app with flask_server.init_flask
.
from flask import Flask
from lexrpc.flask_server import init_flask
# instantiate a Server like above
server = ...
app = Flask('my-server')
init_flask(server, app)
This configures the Flask app to serve the methods registered with the lexrpc server as per the spec. Each method is served at the path /xrpc/[NSID]
, procedures via POSTs and queries via GETs. Parameters are decoded from query parameters, input is taken from the JSON HTTP request body, and output is returned in the JSON HTTP response body. The Content-Type
response header is set to application/json
.
TODO
- support record types, eg via type "ref" and ref field pointing to the nsid example here, ref points to
app.bsky.actor.ref
. ref isn't documented yet though, and these lexicons also use adefs
field, which isn't really documented either. they plan to update the docs and specs soon. - extensions. is there anything to do? ah, they're currently TODO in the spec.
- "binary blob" support. currently undefined ish? is it based on the
encoding
field? - authentication, currently TODO in the spec
Release instructions
Here's how to package, test, and ship a new release.
- Run the unit tests.
source local/bin/activate.csh python3 -m unittest discover
- Bump the version number in
pyproject.toml
anddocs/conf.py
.git grep
the old version number to make sure it only appears in the changelog. Change the current changelog entry inREADME.md
for this new version from unreleased to the current date. - Build the docs. If you added any new modules, add them to the appropriate file(s) in
docs/source/
. Then run./docs/build.sh
. Check that the generated HTML looks fine by openingdocs/_build/html/index.html
and looking around. git commit -am 'release vX.Y'
- Upload to test.pypi.org for testing.
python3 -m build setenv ver X.Y twine upload -r pypitest dist/lexrpc-$ver*
- Install from test.pypi.org.
cd /tmp python3 -m venv local source local/bin/activate.csh pip3 uninstall lexrpc # make sure we force pip to use the uploaded version pip3 install --upgrade pip pip3 install -i https://test.pypi.org/simple --extra-index-url https://pypi.org/simple lexrpc==$ver deactivate
- Smoke test that the code trivially loads and runs.
source local/bin/activate.csh python3 # run test code below deactivate
Test code to paste into the interpreter:from lexrpc import Server server = Server([{ 'lexicon': 1, 'id': 'io.example.ping', 'defs': { 'main': { 'type': 'query', 'description': 'Ping the server', 'parameters': {'message': { 'type': 'string' }}, 'output': { 'encoding': 'application/json', 'schema': { 'type': 'object', 'required': ['message'], 'properties': {'message': { 'type': 'string' }}, }, }, }, }, }]) @server.method('io.example.ping') def ping(input, message=''): return {'message': message} print(server.call('io.example.ping', {}, message='hello world'))
- Tag the release in git. In the tag message editor, delete the generated comments at bottom, leave the first line blank (to omit the release "title" in github), put
### Notable changes
on the second line, then copy and paste this version's changelog contents below it.git tag -a v$ver --cleanup=verbatim git push && git push --tags
- Click here to draft a new release on GitHub. Enter
vX.Y
in the Tag version box. Leave Release title empty. Copy### Notable changes
and the changelog contents into the description text box. - Upload to pypi.org!
twine upload dist/lexrpc-$ver.tar.gz dist/lexrpc-$ver-py3-none-any.whl
- Wait for the docs to build on Read the Docs, then check that they look ok.
- On the Versions page, check that the new version is active, If it's not, activate it in the Activate a Version section.
Changelog
0.2 - 2023-03-13
Bluesky's Lexicon design and schema handling is still actively changing, so this is an interim release. It generally supports the current lexicon design, but not full schema validation yet. I'm not yet trying to fast follow the changes too closely; as they settle down and stabilize, I'll put more effort into matching and fully implementing them. Stay tuned!
Breaking changes:
- Fully migrate to new lexicon format. Original format is no longer supported.
0.1 - 2022-12-13
Initial release!
Tested interoperability with the lexicon
, xprc
, and xrpc-server
packages in bluesky-social/atproto. Lexicon and XRPC themselves are still very early and under active development; caveat hacker!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file lexrpc-0.2.tar.gz
.
File metadata
- Download URL: lexrpc-0.2.tar.gz
- Upload date:
- Size: 12.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.1.1 pkginfo/1.8.1 requests/2.27.1 setuptools/65.6.3 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.16
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | f19f6f2b7bef5e7e6752098e6d89b18dc42b2cfc2f0315d07a40e02120cfefb9 |
|
MD5 | 5ea92c59f09385df6049099cb22059d8 |
|
BLAKE2b-256 | d78ddeb99eb6eeef0c8696ca68d67e96e19adc7fdb6f728b29dbf531cee03853 |
File details
Details for the file lexrpc-0.2-py3-none-any.whl
.
File metadata
- Download URL: lexrpc-0.2-py3-none-any.whl
- Upload date:
- Size: 10.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.1.1 pkginfo/1.8.1 requests/2.27.1 setuptools/65.6.3 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.16
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1f597bf43d96fe6e8643171e774452f60a2bbe23260c1e4acc3ddea8988d9222 |
|
MD5 | a2ce6a2f3417f3bc081f914f68e4fe60 |
|
BLAKE2b-256 | 4e295813b2a554ae3d2232974a7a68a9a93f27f0508c2660b0b7f809512e1896 |