Template for mu.semte.ch-microservices written in Python3. Based on the Flask-framework.
Create a Dockerfile
which extends the semtech/mu-python-template
-image and set a maintainer.
FROM semtech/mu-python-template:2.0.0-beta.1
LABEL maintainer="[email protected]"
Create a web.py
entrypoint-file. (naming of the entrypoint can be configured through APP_ENTRYPOINT
)
@app.route("/hello")
def hello():
return "Hello from the mu-python-template!"
Build the Docker-image for your service
docker build -t my-python-service .
Run your service
docker run -p 8080:80
You now should be able to access your service's endpoint
curl localhost:8080/hello
If your service needs external libraries other than the ones already provided by the template (Flask, SPARQLWrapper and rdflib), you can specify those in a requirements.txt
-file. The template will take care of installing them when you build your Docker image.
By leveraging Dockers' bind-mount, you can mount your application code into an existing service image. This spares you from building a new image to test each change. Just mount your services' folder to the containers' /app
. On top of that, you can configure the environment variable MODE
to development
. That enables live-reloading of the server, so it immediately updates when you save a file.
example docker-compose parameters:
environment:
MODE: "development"
volumes:
- /home/my/code/my-python-service:/app
The template provides the user with several helper methods. They aim to give you a step ahead for:
- logging
- JSONAPI-compliancy
- SPARQL querying
The below helpers can be imported from the helpers
module. For example:
from helpers import *
Available functions:
Works exactly the same as the logging.info method from pythons' logging module.
Logs are written to the /logs directory in the docker container.
Note that the helpers
module also exposes logger
, which is the logger instance used by the template. The methods provided by this instance can be used for more fine-grained logging.
Generate a random UUID (String).
Get the session id from the HTTP request headers.
Get the rewrite URL from the HTTP request headers.
Validate whether the Content-Type header contains the JSONAPI content-type
-header. Returns a 400 otherwise.
Validate whether the type specified in the JSONAPI data is equal to the expected type. Returns a 409 otherwise.
Returns a JSONAPI compliant error Response object with the given status code (default: 400). kwargs
can be any other keys supported by JSONAPI error objects.
Executes the given SPARQL select/ask/construct query.
Executes the given SPARQL update query.
The template provides one other helper module, being the escape_helpers
-module. It contains functions for SPARQL query-escaping. Example import:
from escape_helpers import *
Available functions:
Converts the given object to a SPARQL-safe RDF object string with the right RDF-datatype.
This functions should be used especially when inserting user-input to avoid SPARQL-injection.
Separate functions are available for different python datatypes, the sparql_escape
function however can automatically select the right method to use, for following Python datatypes:
str
int
float
datetime.datetime
datetime.date
datetime.time
boolean
The sparql_escape_uri
-function can be used for escaping URI's.
The template itself is unopinionated when it comes to constructing SPARQL-queries. However, since Python's most common string formatting methods aren't a great fit for SPARQL queries, we hereby want to provide an example on how to construct a query based on template strings while keeping things readable.
from string import Template
from helpers import query
from escape_helpers import sparql_escape_uri
my_person = "http://example.com/me"
query_template = Template("""
PREFIX mu: <http://mu.semte.ch/vocabularies/core/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?name
WHERE {
$person a foaf:Person ;
foaf:firstName ?name .
}
""")
query_string = query_template.substitute(person=sparql_escape_uri(my_person))
query_result = query(query_string)
Example snippet for adding a service to a docker-compose stack:
my-python:
image: my-python-service
environment:
LOG_LEVEL: "debug"
-
LOG_LEVEL
takes the same options as defined in the Python logging module. -
MODE
to specify the deployment mode. Can bedevelopment
as well asproduction
. Defaults toproduction
-
MU_SPARQL_ENDPOINT
is used to configure the SPARQL endpoint.- By default this is set to
http://database:8890/sparql
. In that case the triple store used in the backend should be linked to the microservice container asdatabase
.
- By default this is set to
-
MU_APPLICATION_GRAPH
specifies the graph in the triple store the microservice will work in.- By default this is set to
http://mu.semte.ch/application
. The graph name can be used in the service viasettings.graph
.
- By default this is set to
-
MU_SPARQL_TIMEOUT
is used to configure the timeout (in seconds) for SPARQL queries.
Since this template is based on the meinheld-gunicorn-docker image, all possible environment config for that image is also available for the template. See meinheld-gunicorn-docker#environment-variables for more info. The template configures WEB_CONCURRENCY
in particular to 1
by default.
For hosting the app in a production setting, the template depends on meinheld-gunicorn-docker. All environment variables used by meinheld-gunicorn can be used to configure your service as well.