# SpaceAPI Server [![pipeline status](https://gitlab.com/s3lph/spaceapi-server/badges/master/pipeline.svg)][master] [![coverage report](https://gitlab.com/s3lph/spaceapi-server/badges/master/coverage.svg)][master] A lightweight server for [SpaceAPI][spaceapi] endpoints. Includes support for pluggable templating, so dynamic content, like sensor values, can be added. ## Dependencies - Python 3 (>=3.6) - [Bottle][pypi-bottle] - [Jinja2][pypi-jinja2] ## License [MIT License][mit] ## Usage ```bash python -m spaceapi_server config.json ``` ## Configuration ```json { "address": "::1", # The address to listen on. "port": 8000, # The TCP port to listen on. "server": "wsgiref", # The Bottle backend server to use. "template": "template.json", # Path to the SpaceAPI response template file. "plugins_dir": "plugins", # Path to the directory containing your plugins. "plugins": { # Plugin-specific configuration should go in here, e.g. `.plugins.sqlite.database` } } ``` ## Serve a Static SpaceAPI Endpoint Have a look at [SpaceAPI: Getting Started][spaceapi-getting-started]. If you only want to serve static content, your `template.json` may consist of regular JSON data, which is served almost-as-is (once parsed and re-serialized). ## Add Dynamic Content This example guides you through adding a dynamic `.state` property to your SpaceAPI endpoint. We'll use the following (rather simple, and probably not too useful) data source: Check a certain file, and mark the space as open depending on its existence. 1. Create a plugin to fetch the data. Let's name it `mybackend.py` and put in in our plugins directory: ```python import os from spaceapi_server import config, plugins @plugins.template_function def space_state(): # Get the plugin config dict conf = config.get_plugin_config('mybackend') # Get the filename filename = conf.get('filename', '/var/space_state') try: # Get the file's properties stat = os.stat(filename) except FileNotFoundError: # File doesn't exist, aka. space is closed return { 'open': False } # File exists, aka. space is open. Also report the mtime as "last changed" timestamp return { 'open': True, 'lastchange': int(stat.st_mtime) } ``` The `@template_function` decorator registers the function as a callable in Jinja's globals. There's also `@template_filter`, which registers a Jinja2 filter, and `@template_test`, which registers a test. For more information on the Jinja2 templating engine, see [Jinja2][jinja]. 2. Call the template function in your template: ```json { # ... "state": "{{ space_state() }}" # ... } ``` Although the value for the `state` key is a string containing the Jinja2 template, the return value of your template function is a complex data type, which will be inserted into the result as such. 3. Configure the server: ```json # ... "template": "template.json", "plugins_dir": "plugins", "plugins": { "mybackend": { "filename", "/var/space_state" } } # ... ``` 4. Start the server and query it. [master]: https://gitlab.com/s3lph/spaceapi-server/commits/master [spaceapi]: https://spaceapi.io/ [pypi-bottle]: https://pypi.org/project/bottle/ [pypi-jinja2]: https://pypi.org/project/Jinja2/ [mit]: https://gitlab.com/s3lph/spaceapi-server/blob/master/LICENSE [spaceapi-getting-started]: https://spaceapi.io/getting-started/ [jinja]: https://jinja.palletsprojects.com/