curl
and jq
are used. However, the real intention here is to show other programmers how they could implement a client in their language on top of the HTTP API. For an example of how to build a client on top of gRPC, refer to the implementation of the Go client. Similar to the Go client example, we use a bank account transfer example. Create the clientA client built on top of the HTTP API needs to track three pieces of state for each transaction.
start_ts
). This uniquely identifies a transaction, and doesn’t change over the transaction lifecycle.keys
). This aids in transaction conflict detection. Every mutation would send back a new set of keys. The client must merge them with the existing set. Optionally, a client can de-dup these keys while merging.preds
). This aids in predicate move detection. Every mutation would send back a new set of predicates. The client must merge them with the existing set. Optionally, a client can de-dup these keys while merging./alter
endpoint:
curl "localhost:8080/alter" --silent --request POST \
--data $'
name: string @index(term) .
release_date: datetime @index(year) .
revenue: float .
running_time: int .
starring: [uid] .
director: [uid] .
type Person {
name
}
type Film {
name
release_date
revenue
running_time
starring
director
}
' | python -m json.tool
The success response looks like:
{
"data": {
"code": "Success",
"message": "Done"
}
}
In case of errors, the API returns an error message such as:
{
"errors": [
{
"extensions": {
"code": "Error"
},
"message": "line 5 column 18: Invalid ending"
}
]
}
The request updates or creates the predicates and types present in the request. It doesn’t modify or delete other schema information that may be present.
Query current DQL schemaObtain the DQL schema by issuing a DQL query on/query
endpoint.
$ curl -X POST \
-H "Content-Type: application/dql" \
localhost:8080/query -d $'schema {}' | python -m json.tool
Start a transactionAssume some initial accounts with balances have been populated. We now want to transfer money from one account to the other. This is done in four steps:
start_ts
can initially be set to 0. keys
can start as an empty set. For both query and mutation if the start_ts
is provided as a path parameter, then the operation is performed as part of the ongoing transaction. Otherwise, a new transaction is initiated. Run a queryTo query the database, the /query
endpoint is used. Remember to set the Content-Type
header to application/dql
to ensure that the body of the request is parsed correctly. To get the balances for both accounts:
$ curl -H "Content-Type: application/dql" -X POST localhost:8080/query -d $'
{
balances(func: anyofterms(name, "Alice Bob")) {
uid
name
balance
}
}' | jq
The result should look like this:
{
"data": {
"balances": [
{
"uid": "0x1",
"name": "Alice",
"balance": "100"
},
{
"uid": "0x2",
"name": "Bob",
"balance": "70"
}
]
},
"extensions": {
"server_latency": {
"parsing_ns": 70494,
"processing_ns": 697140,
"encoding_ns": 1560151
},
"txn": {
"start_ts": 4
}
}
}
Notice that along with the query result under the data
field is additional data in the extensions -> txn
field. This data has to be tracked by the client. For queries, there is a start_ts
in the response. This start_ts
needs to be used in all subsequent interactions with Dgraph for this transaction, and so should become part of the transaction state. Run a mutationMutations can be done over HTTP by making a POST
request to an Alpha’s /mutate
endpoint. We need to send a mutation to Dgraph with the updated balances. If Bob transfers $10 to Alice, then the RDF triples to send are:
<0x1> <balance> "110" .
<0x1> <dgraph.type> "Balance" .
<0x2> <balance> "60" .
<0x2> <dgraph.type> "Balance" .
Note that refer to the Alice and Bob nodes by UID in the RDF format. We now send the mutations via the /mutate
endpoint. We need to provide our transaction start timestamp as a path parameter, so that Dgraph knows which transaction the mutation should be part of. We also need to set Content-Type
header to application/rdf
to specify that mutation is written in RDF format.
$ curl -H "Content-Type: application/rdf" -X POST localhost:8080/mutate?startTs=4 -d $'
{
set {
<0x1> <balance> "110" .
<0x1> <dgraph.type> "Balance" .
<0x2> <balance> "60" .
<0x2> <dgraph.type> "Balance" .
}
}
' | jq
The result:
{
"data": {
"code": "Success",
"message": "Done",
"uids": {}
},
"extensions": {
"server_latency": {
"parsing_ns": 50901,
"processing_ns": 14631082
},
"txn": {
"start_ts": 4,
"keys": ["2ahy9oh4s9csc", "3ekeez23q5149"],
"preds": ["1-balance"]
}
}
}
The result contains keys
and predicates
which should be added to the transaction state. Committing the transaction
It is possible to commit immediately after a mutation is made (without requiring to use the /commit
endpoint as explained in this section). To do this, add the parameter commitNow
in the URL /mutate?commitNow=true
.
/commit
endpoint. We need the start_ts
we’ve been using for the transaction along with the list of keys
and the list of predicates. If we had performed multiple mutations in the transaction instead of just one, then the keys and predicates provided during the commit would be the union of all keys and predicates returned in the responses from the /mutate
endpoint. The preds
field is used to cancel the transaction in cases where some of the predicates are moved. This field isn’t required and the /commit
endpoint also accepts the old format, which was a single array of keys.
$ curl -X POST localhost:8080/commit?startTs=4 -d $'
{
"keys": [
"2ahy9oh4s9csc",
"3ekeez23q5149"
],
"preds": [
"1-balance"
]
}' | jq
The result:
{
"data": {
"code": "Success",
"message": "Done"
},
"extensions": {
"txn": {
"start_ts": 4,
"commit_ts": 5
}
}
}
The transaction is now complete. If another client were to perform another transaction concurrently affecting the same keys, then it’s possible that the transaction would not be successful. This is indicated in the response when the commit is attempted.
{
"errors": [
{
"code": "Error",
"message": "Transaction has been aborted. Please retry."
}
]
}
In this case, it should be up to the user of the client to decide if they wish to retry the transaction. Cancelling the transactionTo cancel a transaction, use the same /commit
endpoint with the abort=true
parameter while specifying the startTs
value for the transaction.
curl -X POST "localhost:8080/commit?startTs=4&abort=true" | jq
The result:
{
"code": "Success",
"message": "Done"
}
Running read-only queriesYou can set the query parameter ro=true
to /query
to set it as a read-only query.
$ curl -H "Content-Type: application/dql" -X POST "localhost:8080/query?ro=true" -d $'
{
balances(func: anyofterms(name, "Alice Bob")) {
uid
name
balance
}
}
Running best-effort queries
$ curl -H "Content-Type: application/dql" -X POST "localhost:8080/query?be=true" -d $'
{
balances(func: anyofterms(name, "Alice Bob")) {
uid
name
balance
}
}
Compression via HTTPDgraph supports gzip-compressed requests to and from Dgraph Alphas for /query
, /mutate
, and /alter
. Compressed requests: to send compressed requests, set the HTTP request header Content-Encoding: gzip
along with the gzip-compressed payload. Compressed responses: to receive compressed responses, set the HTTP request header Accept-Encoding: gzip
. Example of a compressed request via curl:
$ curl -X POST \
-H 'Content-Encoding: gzip' \
-H "Content-Type: application/rdf" \
localhost:8080/mutate?commitNow=true --data-binary @mutation.gz
Example of a compressed request via curl:
$ curl -X POST \
-H 'Accept-Encoding: gzip' \
-H "Content-Type: application/dql" \
localhost:8080/query -d $'schema {}' | gzip --decompress
Example of a compressed request and response via curl:
$ zcat query.gz # query.gz is gzipped compressed
{
all(func: anyofterms(name, "Alice Bob")) {
uid
balance
}
}
$ curl -X POST \
-H 'Content-Encoding: gzip' \
-H 'Accept-Encoding: gzip' \
-H "Content-Type: application/dql" \
localhost:8080/query --data-binary @query.gz | gzip --decompress
Curl has a --compressed
option that automatically requests for a compressed response (Accept-Encoding
header) and decompresses the compressed response.
curl -X POST --compressed -H "Content-Type: application/dql" localhost:8080/query -d $'schema {}'
Run a query in JSON formatThe HTTP API also accepts requests in JSON format. For queries you have the keys query
and variables
. The JSON format is required to set GraphQL Variables with the HTTP API. This query:
{
balances(func: anyofterms(name, "Alice Bob")) {
uid
name
balance
}
}
Should be escaped to this:
curl -H "Content-Type: application/json" localhost:8080/query -XPOST -d '{
"query": "{\n balances(func: anyofterms(name, \"Alice Bob\")) {\n uid\n name\n balance\n }\n }"
}' | python -m json.tool | jq
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4