Ontology SPARQL Endpoint
Deploy a fully functional SPARQL 1.1 endpoint from any RDF repository. Uses pyoxigraph (Python bindings for the Oxigraph graph database) for storage and querying, and Python's built-in HTTP server for the endpoint.
Single script: scripts/deploy_endpoint.py
Features
- SPARQL 1.1 Query —
SELECT,ASK,CONSTRUCT,DESCRIBE - SPARQL 1.1 Update —
INSERT DATA,DELETE DATA,DELETE/INSERT - YASGUI Web UI — point your browser to
http://localhost:7878/ - Persistent storage — data survives restarts (RocksDB-backed)
- Bulk load — merges all RDF files with rdflib, loads via N-Triples
- Add data via HTTP —
POST /storewith Turtle/N-Triples/RDF-XML
Setup
cd <your-ontology-repo>
python3 -m venv .venv
source .venv/bin/activate
pip install rdflib pyoxigraph
After finishing: deactivate the venv and remove it:
deactivate && rm -rf .venvSkip this if the user asks to keep the environment.
pyoxigraphis a pre-compiled Python wheel — no Rust toolchain, no Java, no binary downloads needed.
Usage
Load data and start endpoint
python scripts/deploy_endpoint.py . --port 7878
This merges all RDF files, bulk-loads them, and starts the HTTP server.
Just load data (no server)
python scripts/deploy_endpoint.py . --no-serve --data-dir oxigraph_data/
Serve existing data without reloading
python scripts/deploy_endpoint.py . --serve-only --data-dir oxigraph_data/
Query examples
# SELECT via curl
curl -X POST http://localhost:7878/query \
-H 'Content-Type: application/sparql-query' \
--data 'SELECT * WHERE { ?s ?p ?o } LIMIT 10'
# ASK
curl -X POST http://localhost:7878/query \
-H 'Content-Type: application/sparql-query' \
--data 'ASK WHERE { ?s a <http://example.com/skos#Concept> }'
# CONSTRUCT (returns Turtle)
curl -X POST http://localhost:7878/query \
-H 'Content-Type: application/sparql-query' \
--data 'CONSTRUCT WHERE { ?s ?p ?o } LIMIT 5'
Add data via HTTP
curl -X POST http://localhost:7878/store \
-H 'Content-Type: text/turtle' -T new_data.ttl
SPARQL Update
curl -X POST http://localhost:7878/update \
-H 'Content-Type: application/sparql-update' \
--data 'INSERT DATA { <http://example.com/s> <http://example.com/p> "hello"@en }'
Architecture
┌─────────────────────┐
│ RDF files in repo │
│ (.ttl, .owl, …) │
└────────┬────────────┘
│ rdflib merge + N-Triples serialize
▼
┌─────────────────────┐
│ pyoxigraph Store │
│ (RocksDB on disk) │
└────────┬────────────┘
│ Python http.server
▼
┌─────────────────────┐
│ HTTP SPARQL endpoint│
│ /query — SELECT, │
│ ASK, │
│ CONSTRUCT │
│ /update — SPARQL │
│ Update │
│ /store — Graph │
│ Store │
│ / — YASGUI │
└─────────────────────┘
Output Files
Never write files into the repository without permission. Before generating
any report or output file, ask the user where to save it (e.g. -o ../report.md
or an absolute path outside the repo). The default output path in script
examples is only a suggestion — always confirm with the user first.
Limitations
Not production-hardened. Python's
http.serveris single-threaded. For production, use the Oxigraph CLI binary (oxigraph serve --location oxigraph_data/), which is multi-threaded and includes the full SPARQL 1.1 Protocol with content negotiation.No authentication. The endpoint is open. Add a reverse proxy (nginx) for authentication in production.
Graph Store protocol is partial. Only
POST /storeis implemented (add data). NoGET /store?graph=(retrieve by graph) yet.
Scaling Up
For production or large datasets (> 100K triples), use the native Oxigraph binary instead of the Python wrapper:
# Install once
cargo install oxigraph-cli
# or download from https://github.com/oxigraph/oxigraph/releases
# Load data
oxigraph load --location oxigraph_data/ --file merged.nt
# Serve (multi-threaded, full protocol)
oxigraph serve --location oxigraph_data/ --bind 0.0.0.0:7878