33
44Python implementation of `AT Protocol <https://atproto.com/ >`__\ ’s
55`XRPC <https://atproto.com/specs/xrpc >`__ +
6- `Lexicon <https://atproto.com/guides/lexicon >`__, both client and
7- server. `Docs here. <https://lexrpc.readthedocs.io/ >`__
8-
9- - `Getting started <#getting-started >`__
10-
11- - `Client <#client >`__
12- - `Server <#server >`__
13- - `Flask server <#flask-server >`__
14-
6+ `Lexicon <https://atproto.com/guides/lexicon >`__. lexrpc includes a
7+ simple `XRPC <https://atproto.com/specs/xrpc >`__ client, server, and
8+ `Flask <https://flask.palletsprojects.com/ >`__ web server integration.
9+ All three include full `Lexicon <https://atproto.com/guides/lexicon >`__
10+ support for validating inputs, outputs, and parameters against their
11+ schemas.
12+
13+ - `Client <#client >`__
14+ - `Server <#server >`__
15+ - `Flask server <#flask-server >`__
16+ - `Reference <https://lexrpc.readthedocs.io/en/docs/source/lexrpc.html >`__
1517- `TODO <#todo >`__
1618- `Changelog <#changelog >`__
1719
1820License: This project is placed in the public domain.
1921
20- Getting started
21- ---------------
22-
23- lexrpc includes a simple `XRPC <https://atproto.com/specs/xrpc >`__
24- client, server, and `Flask <https://flask.palletsprojects.com/ >`__ web
25- server integration. All three include full
26- `Lexicon <https://atproto.com/guides/lexicon >`__ support for validating
27- inputs, outputs, and parameters against their schemas.
28-
2922Client
30- ~~~~~~
23+ ------
3124
3225The lexrpc client let you `call methods dynamically by their
3326NSIDs <https://atproto.com/guides/lexicon#rpc-methods> `__. To make a
3427call, first instantiate a
3528`Client <https://lexrpc.readthedocs.io/en/latest/source/lexrpc.html#lexrpc.client.Client >`__
36- object with the server address and method lexicons, then use NSIDs to
37- make calls, passing input as a dict and parameters as kwargs:
29+ object with the server address and method lexicons, then use method
30+ NSIDs to make calls, passing input as a dict and parameters as kwargs:
3831
3932.. code :: py
4033
41- from jsonschema import Client
34+ from lexrpc import Client
4235
4336 lexicons = [... ]
4437 client = Client(' https://xrpc.example.com' , lexicons)
45- output = client.com.example.my_query({' foo' : ' bar' }, a_param = False )
38+ output = client.com.example.my_query({' foo' : ' bar' }, param_a = 5 )
4639
4740 Note that ``- `` characters in method NSIDs are converted to ``_ ``\ s, eg
4841the call above is for the method ``com.example.my-query ``.
4942
5043Server
51- ~~~~~~
44+ ------
5245
5346To implement an XRPC server, use the
5447`Server <https://lexrpc.readthedocs.io/en/latest/source/lexrpc.html#lexrpc.server.Server >`__
5548class. It validates parameters, inputs, and outputs. Use the
5649`method <https://lexrpc.readthedocs.io/en/latest/source/lexrpc.html#lexrpc.server.Server.method >`__
57- decorator to register handlers for each NSID,
58- `Server. call <https://lexrpc.readthedocs.io/en/latest/source/lexrpc.html#lexrpc.server.Server.call >`__
59- to call a method from your web framework or anywhere else.
50+ decorator to register method handlers and
51+ `call <https://lexrpc.readthedocs.io/en/latest/source/lexrpc.html#lexrpc.server.Server.call >`__
52+ to call them, whether from your web framework or anywhere else.
6053
6154.. code :: py
6255
63- from jsonschema import Server
56+ from lexrpc import Server
6457
6558 lexicons = [... ]
6659 server = Server(lexicons)
6760
6861 @server.method (' com.example.my-query' )
6962 def my_query_hander (input , ** params ):
70- ...
71- output = ...
63+ output = {' foo' : input [' foo' ], ' b' : params[' param_a' ] + 1 }
7264 return output
7365
74- # In your web framework, use Server.call to run a method
66+ # Extract nsid and decode query parameters from an HTTP request,
67+ # call the method, return the output in an HTTP response
68+ nsid = request.path.removeprefix(' /xrpc/' )
7569 input = request.json()
76- params = request.query_params()
77- # decode params
70+ params = server.decode_params(nsid, request.query_params())
7871 output = server.call(input , ** params)
7972 response.write_json(output)
8073
8174 Flask server
82- ~~~~~~~~~~~~
75+ ------------
8376
84- First, instantiate a ``Server `` and register method handlers as
85- described above. Then, attach the server to your Flask app with
86- `lexrpc.init_flask <https://lexrpc.readthedocs.io/en/latest/source/lexrpc.html#lexrpc.flask_server.init_flask >`__.
77+ To serve XRPC methods in a
78+ `Flask <https://flask.palletsprojects.com/ >`__ web app, first install
79+ the lexrpc package with the ``flask `` extra, eg
80+ ``pip install lexrpc[flask] ``. Then, instantiate a
81+ `Server <https://lexrpc.readthedocs.io/en/latest/source/lexrpc.html#lexrpc.server.Server >`__
82+ and register method handlers as described above. Finally, attach the
83+ server to your Flask app with
84+ `flask_server.init_flask <https://lexrpc.readthedocs.io/en/latest/source/lexrpc.html#lexrpc.flask_server.init_flask >`__.
8785
8886.. code :: py
8987
9088 from flask import Flask
91- from lexrpc import init_flask
89+ from lexrpc.flask_server import init_flask
90+
91+ # instantiate a Server like above
92+ server = ...
9293
9394 app = Flask(' my-server' )
94- ...
9595 init_flask(server, app)
9696
9797 This configures the Flask app to serve the methods registered with the
@@ -105,20 +105,104 @@ set to ``application/json``.
105105TODO
106106----
107107
108- - validate records/tokens in input/output? or are those only
109- primitives?
110- - extensions, https://atproto.com/guides/lexicon#extensibility . is
111- there anything to do? ah, it’s currently TODO in the spec:
112- https://atproto.com/specs/xrpc#todos
113- - “binary blob” support, as in https://atproto.com/specs/xrpc . is it
114- currently undefined?
115- - authentication, currently TODO in the spec:
116- https://atproto.com/specs/xrpc#todos
108+ - support record types, eg via type “ref” and ref field pointing to the
109+ nsid `example
110+ here <https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/graph/follow.json#L13> `__,
111+ ref points to
112+ `app.bsky.actor.ref <https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/actor/ref.json >`__.
113+ ref isn’t documented yet though, and these lexicons also use a
114+ ``defs `` field, which isn’t really documented either. `they plan to
115+ update the docs and specs
116+ soon. <https://github.com/bluesky-social/atproto/pull/409#issuecomment-1348766856> `__
117+ - `extensions <https://atproto.com/guides/lexicon#extensibility >`__. is
118+ there anything to do? ah, `they’re currently TODO in the
119+ spec <https://atproto.com/specs/xrpc#todos> `__.
120+ - `“binary blob” support. <https://atproto.com/specs/xrpc >`__ currently
121+ undefined ish? is it based on the ``encoding `` field?
122+ - `authentication, currently TODO in the
123+ spec <https://atproto.com/specs/xrpc#todos> `__
124+
125+ Release instructions
126+ --------------------
127+
128+ Here’s how to package, test, and ship a new release. (Note that this is
129+ `largely duplicated in the oauth-dropins readme
130+ too <https://github.com/snarfed/oauth-dropins#release-instructions> `__.)
131+
132+ 1. Run the unit tests.
133+ ``sh source local/bin/activate.csh python3 -m unittest discover ``
134+
135+ 2. Bump the version number in ``setup.py `` and ``docs/conf.py ``.
136+ ``git grep `` the old version number to make sure it only appears in
137+ the changelog. Change the current changelog entry in ``README.md ``
138+ for this new version from *unreleased * to the current date.
139+
140+ 3. Build the docs. If you added any new modules, add them to the
141+ appropriate file(s) in ``docs/source/ ``. Then run
142+ ``./docs/build.sh ``. Check that the generated HTML looks fine by
143+ opening ``docs/_build/html/index.html `` and looking around.
144+
145+ 4. ``git commit -am 'release vX.Y' ``
146+
147+ 5. Upload to `test.pypi.org <https://test.pypi.org/ >`__ for testing.
148+ ``sh python3 -m build setenv ver X.Y twine upload -r pypitest dist/lexrpc-$ver* ``
149+
150+ 6. Install from test.pypi.org.
151+ ``sh 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 ``
152+
153+ 7. Smoke test that the code trivially loads and runs.
154+ ``sh source local/bin/activate.csh python3 # run test code below deactivate ``
155+ Test code to paste into the interpreter: \` py from lexrpc import
156+ Server
157+
158+ server = Server([{ ‘lexicon’: 1, ‘id’: ‘io.example.ping’, ‘defs’: {
159+ ‘main’: { ‘type’: ‘query’, ‘description’: ‘Ping the server’,
160+ ‘parameters’: {‘message’: { ‘type’: ‘string’ }}, ‘output’: {
161+ ‘encoding’: ‘application/json’, ‘schema’: { ‘type’: ‘object’,
162+ ‘required’: [‘message’], ‘properties’: {‘message’: { ‘type’:
163+ ‘string’ }}, }, }, }, }, }])
164+
165+ @server.method(‘io.example.ping’) def ping(input, message=’‘):
166+ return {’message’: message}
167+
168+ print(server.call(‘io.example.ping’, {}, message=‘hello world’))
169+ \` `\`
170+
171+ 8. Tag the release in git. In the tag message editor, delete the
172+ generated comments at bottom, leave the first line blank (to omit
173+ the release “title” in github), put ``### Notable changes `` on the
174+ second line, then copy and paste this version’s changelog contents
175+ below it.
176+ ``sh git tag -a v$ver --cleanup=verbatim git push && git push --tags ``
177+
178+ 9. `Click here to draft a new release on
179+ GitHub. <https://github.com/snarfed/lexrpc/releases/new> `__ Enter
180+ ``vX.Y `` in the *Tag version * box. Leave *Release title * empty. Copy
181+ ``### Notable changes `` and the changelog contents into the
182+ description text box.
183+
184+ 10. Upload to `pypi.org <https://pypi.org/ >`__!
185+ ``sh twine upload dist/lexrpc-$ver* ``
186+
187+ 11. `Wait for the docs to build on Read the
188+ Docs <https://readthedocs.org/projects/lexrpc/builds/> `__, then
189+ check that they look ok.
190+
191+ 12. On the `Versions
192+ page <https://readthedocs.org/projects/lexrpc/versions/> `__, check
193+ that the new version is active, If it’s not, activate it in the
194+ *Activate a Version * section.
117195
118196Changelog
119197---------
120198
121- 0.1 - unreleased
199+ 0.1 - 2022-12-13
122200~~~~~~~~~~~~~~~~
123201
124202Initial release!
203+
204+ Tested interoperability with the ``lexicon ``, ``xprc ``, and
205+ ``xrpc-server `` packages in
206+ `bluesky-social/atproto <https://github.com/bluesky-social/atproto >`__.
207+ Lexicon and XRPC are still very early and under active development;
208+ caveat hacker!
0 commit comments