Skip to content
Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


A flask web application for storing JSON documents; with some special functions for JSON-LD.

  Access tokens
  Activity Stream


  • create virtual environment: $ python3 -m venv venv
  • activate virtual environment: $ source venv/bin/activate
  • install requirements: $ pip install -r requirements.txt
  • depending on the type of database you are going to use, you might need to install an additional Python database driver (see SQLAlchemy supported databases)


section key default explanation
environment db_uri sqlite:///keep.db a SQLAlchemy database URI
server_url http://localhost:5000 server URL beginning with the schema and ending with the TLD or port, without any path
(e.g. but not
log_file /tmp/jk_log.txt file system path to the log file
api api_path api specifies the endpoint for API access
(e.g. json or
userdocs_added_properties [] list of additional attributes that are returned by the /userdocs endpoint, if they are contained in a document
garbage_collection_interval -1 garbage collection interval in seconds (value <=0 deactivates gargabe collection)
garbage_collection_age -1 time in seconds that has to pass after the creation or last update of a document without access restriction in order for it to be considered garbage
documents with access restriction are never automatically deleted
firebase service_account_key_file None can be set for Google Firebase integration (details below)
json-ld rewrite_types [] comma seperated list of JSON-LD types for which @id should be set to a dereferencable URL (details below)
activity_stream collection_endpoint None path under which an Activity Stream Collection should be served (e.g. as/collection.json (details below)
activity_generating_types [] comma seperated list of JSON-LD types for which Activites (Create, Reference, Offer) should be created



$ source venv/bin/activate
$ python3 debug


Apache2 + gunicorn example

  • configure server URL in config.ini:

      server_url = http://localhost
  • add proxy rules to apache (e.g. in /etc/apache2/sites-enabled/000-default.conf within the <VirtualHost *:80> block):

      ProxyPassMatch "^/JSONkeeper/(.*)" "http://localhost:5000/JSONkeeper/$1"
      ProxyPassReverse "^/JSONkeeper/(.*)" "http://localhost:5000/JSONkeeper/$1"
  • restart apache, get and start gunicorn

      $ sudo a2enmod proxy_http
      $ sudo service apache2 reload
      $ source venv/bin/activate
      $ pip install gunicorn
      $ gunicorn --bind localhost:5000 -e SCRIPT_NAME='/JSONkeeper' 'jsonkeeper:create_app()'



  • if you make changes to the code, basic testing can be done with

      $ flake8 *.py jsonkeeper/*.py util/*.py
      $ source venv/bin/activate
      $ ./

Usage examples


$ curl -X POST \
       -d '{"foo":"bar"}' \
       -H 'Accept: application/json' \
       -H 'Content-Type: application/json' \




$ curl -X GET \
       -H 'Accept: application/json' \

HTTP/1.0 200 OK



$ curl -X PUT \
       -d '{"bar":"baz"}' \
       -H 'Accept: application/json' \
       -H 'Content-Type: application/json' \

HTTP/1.0 200 OK



$ curl -X DELETE  \

HTTP/1.0 200 OK

Access tokens

Restricting access

  • Firebase (if the configuration points to a valid Firebase service account key file)
    • provide a header X-Firebase-ID-Token when creating a JSON document
    • the document will only be created if the ID token can be verified, otherwise a 403 FORBIDDEN is returned; if the document is created, the application stores the authenticated user's UID
    • subsequent PUT and DELETE requests are only executed when a X-Firebase-ID-Token header is provided that, when decoded, results in the same UID, otherwise a 403 FORBIDDEN is returned
  • Self managed
    • provide a header X-Access-Token when creating a JSON document
    • subsequent PUT and DELETE requests are only executed when a X-Access-Token header with the same value is provided, otherwise a 403 FORBIDDEN is returned
    • NOTE: client software that self manages access tokens should be written with the possibility of collisions (distinct clients assigning the same token for non identical users) in mind (using UUIDs as tokens would be a way to make collisions unlikely)

List of documents for a given token

Accessing /<api_path>/userdocs will return a list of all hosted documents with a matching access token. This means

  • no access token → no documents (documents posted without access token will not be listed)
  • X-Access-Token → all documents created with this token
  • X-Firebase-ID-Token → all documents created by this user


JSON­keeper can be configured to host JSON-LD documents in a sensible manner.


If the configuration contains a section

rewrite_types =,

and a POST request is issued with Content-Type set to application/ld+json and the request's content is a valid JSON-LD document whose expanded @type is listed in the configuration, then the document's @id is set to the URL where JSON­keeper will serve the document.

Special behaviour is defined for nodes within the Curation also are assigned a dereferencable @id.

Activity Stream

JSON­keeper can be configured to serve an Activity Stream that implements the IIIF Change Discovery API 0.1 at conformance level 2. This means a complete change list for respective JSON-LD documents is generated, allowing other applications to stay in sync with JSON­keeper in an effective manner.

Special behaviour is defined for, for which additional Reference and Offer Activities are generated.

NOTE: For JSON-LD documents that are posted without any access restriction (X-Access-Token or X-Firebase-ID-Token) no Activities will be generated.

Unlisted JSON documents

To prevent access restricted JSON documents to appear in the Activity Stream, a header X-Unlisted with the value true can be provided when creating, but not changed when updating.

To manage a document's unlisted setting use /<api_path>/<json_id>/status. A GET requests will yield metadata associated with the JSON document. A value update is possible through a PATCH request with a payload in the form of {"unlisted": <value>}, where <value> can be true or false.


The JSON­keeper logo uses image content from 十二類絵巻 in the 日本古典籍データセット(国文研所蔵) provided by the Center for Open Data in the Humanities, used under CC-BY-SA 4.0. The JSON­keeper logo itself is licensed under CC-BY-SA 4.0 by Tarek Saier. A high resolution version (3052×2488 px) can be downloaded here.


Sponsored by the National Institute of Informatics.
Supported by the Center for Open Data in the Humanities, Joint Support-Center for Data Science Research, Research Organization of Information and Systems.


A flask web application for storing JSON documents; with some special functions for JSON-LD.




No packages published