Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Graph Store Protocol

Fluree implements the W3C SPARQL 1.1 Graph Store HTTP Protocol: read, replace, add to, or remove one graph with plain HTTP verbs. RDF tools that speak the protocol (Apache Jena, RDF4J, rdflib and others) can use Fluree as a graph store without a Fluree-specific client.

URL

/v1/fluree/data/{ledger}?graph={graph-iri}
/v1/fluree/data/{ledger}?default

graph= names a graph by its absolute IRI (percent-encode it). A bare default names the ledger’s default graph. A request names exactly one of the two; neither or both is a 400. The ledger’s system graphs (#txn-meta, #config) cannot be addressed here.

GET and HEAD read a past state when the ledger carries a time pin, in any form /query/{ledger} accepts: /v1/fluree/data/mydb:main@t:5?graph={graph-iri} returns the graph as it was at t=5, and a graph that did not exist yet is a 404.

This is the protocol’s indirect graph identification. Direct identification, where the request URL is itself the graph IRI, is not supported: Fluree’s graph IRIs are not URLs on the server.

Methods

MethodDoesSuccess
GETReturns the graph’s triples, the whole graph in one response200; 404 if the graph does not exist
HEADSame status and Content-Type as GET, without building the graph200 / 404
PUTReplaces the graph’s contents with the body201 if this created the graph, otherwise 200
POSTAdds the body’s triples to the graph201 if this created the graph, otherwise 200
DELETERemoves the graph (the default graph is emptied)200; 404 if the graph does not exist

PUT, POST and DELETE respond with the standard transaction response (ledger, t, tx-id, commit). Other statuses: 400 for a malformed request or body, 406 when GET can’t produce any format in Accept, 415 for an unsupported body type, and the usual 401 / 403 for auth.

PUT: replace

PUT is graph sync: one commit holding only the difference between the graph’s current contents and the body. Triples already there are not retracted and re-asserted, so replacing a large graph with a small change is a small commit, and an unchanged body commits nothing.

As the protocol specifies, an empty PUT body empties the graph. Unlike /sync, there is no allowEmpty opt-in: the method is the explicit replace.

POST: add

POST inserts the body’s triples into the graph and retracts nothing. Blank nodes are fresh on every request (an RDF merge), so posting the same document with [ … ] nodes twice adds two copies of those nodes. Use PUT when you want the graph to match a document. An empty POST body is a 400: there is nothing to add.

DELETE: remove

DELETE on a named graph is DROP GRAPH; on the default graph it is CLEAR DEFAULT.

Graph existence

Fluree has no empty named graph: a named graph exists while it holds at least one triple. So after a DELETE, or a PUT with an empty body, GET on that graph is a 404. The default graph always exists.

For GET and HEAD, existence is as the caller sees it: a named graph with no triple the caller may read is a 404, the same answer as a graph that isn’t there. Authentication runs first, so an unauthenticated read is a 401 whether or not the graph exists.

GET is not paged. It builds and serializes the whole graph before responding, so for a large graph, query it through /query with LIMIT / OFFSET, or export the ledger.

Formats

PUT and POST accept:

Content-TypeBody
text/turtleTurtle
application/n-triplesN-Triples
application/trigTriG: triples in GRAPH blocks naming the request’s graph, or outside any block, but not both
application/ld+json, application/jsonInsert-shaped JSON-LD

The TriG rules are those of sync: every block must name the request’s graph, a block for another graph is a 400, and a body targeting the default graph cannot contain blocks.

GET answers in the highest-weighted (q) format in Accept that it supports; equal weights keep the header’s order:

AcceptResponse
application/ld+json, application/json, */*, application/*, or no AcceptJSON-LD
text/turtle (or text/*)Turtle
application/n-triplesN-Triples
application/rdf+xmlRDF/XML

An Accept that names none of these is a 406. The Turtle and N-Triples a GET returns are what PUT accepts, so a graph read as Turtle and put back unchanged commits nothing: blank nodes are written under their stored labels, which a write resolves back to the same nodes.

Edge annotations are returned with their edges: ex:alice ex:knows ex:bob ~ ex:claim1 in Turtle, an rdf:reifies line in N-Triples, @annotation in JSON-LD, the rdf:annotation attribute in RDF/XML (see Edge annotations). A graph with annotations therefore survives a GET followed by a PUT of the result, too. The annotation lookup adds about a quarter to the read, even when no triple in the graph is annotated, so it runs only on a ledger that has held an annotation at some point; once a ledger has, every read pays it.

Auth and policy

GET runs a SPARQL CONSTRUCT of the graph through the query path, and HEAD an ASK, so read policy applies exactly as it does for /query: a restricted reader sees only what policy allows, and the 404 follows what they can see.

PUT, POST and DELETE need write access to the ledger, as /insert does. Modify policy applies to the staged changes. As with sync, the scan of a graph’s current contents that PUT diffs against is not view-policy filtered.

Clusters

Reads are served by whichever node receives them. Writes go through consensus: on a Raft follower they are forwarded to the leader, and on a peer they are forwarded to the transaction server.

Examples

# Replace a graph with a Turtle file
curl -X PUT "http://localhost:8090/v1/fluree/data/mydb:main?graph=urn:example:tools" \
  -H "Content-Type: text/turtle" \
  --data-binary @tools.ttl

# Add triples to it
curl -X POST "http://localhost:8090/v1/fluree/data/mydb:main?graph=urn:example:tools" \
  -H "Content-Type: text/turtle" \
  --data-binary @more.ttl

# Read it back
curl "http://localhost:8090/v1/fluree/data/mydb:main?graph=urn:example:tools" \
  -H "Accept: text/turtle"

# Replace the default graph
curl -X PUT "http://localhost:8090/v1/fluree/data/mydb:main?default" \
  -H "Content-Type: text/turtle" \
  --data-binary @data.ttl

# Remove the graph
curl -X DELETE "http://localhost:8090/v1/fluree/data/mydb:main?graph=urn:example:tools"