github.com/dgraph-io/dgraph@v1.2.8/wiki/content/clients/index.md (about)

     1  +++
     2  date = "2017-03-20T19:35:35+11:00"
     3  title = "Clients"
     4  +++
     5  
     6  ## Implementation
     7  
     8  Clients can communicate with the server in two different ways:
     9  
    10  - **Via [gRPC](http://www.grpc.io/).** Internally this uses [Protocol
    11    Buffers](https://developers.google.com/protocol-buffers) (the proto file
    12  used by Dgraph is located at
    13  [api.proto](https://github.com/dgraph-io/dgo/blob/master/protos/api.proto)).
    14  
    15  - **Via HTTP.** There are various endpoints, each accepting and returning JSON.
    16    There is a one to one correspondence between the HTTP endpoints and the gRPC
    17  service methods.
    18  
    19  
    20  It's possible to interface with Dgraph directly via gRPC or HTTP. However, if a
    21  client library exists for you language, this will be an easier option.
    22  
    23  {{% notice "tip" %}}
    24  For multi-node setups, predicates are assigned to the group that first sees that
    25  predicate. Dgraph also automatically moves predicate data to different groups in
    26  order to balance predicate distribution. This occurs automatically every 10
    27  minutes. It's possible for clients to aid this process by communicating with all
    28  Dgraph instances. For the Go client, this means passing in one
    29  `*grpc.ClientConn` per Dgraph instance. Mutations will be made in a round robin
    30  fashion, resulting in an initially semi random predicate distribution.
    31  {{% /notice %}}
    32  
    33  ### Transactions
    34  
    35  Dgraph clients perform mutations and queries using transactions. A
    36  transaction bounds a sequence of queries and mutations that are committed by
    37  Dgraph as a single unit: that is, on commit, either all the changes are accepted
    38  by Dgraph or none are.
    39  
    40  A transaction always sees the database state at the moment it began, plus any
    41  changes it makes --- changes from concurrent transactions aren't visible.
    42  
    43  On commit, Dgraph will abort a transaction, rather than committing changes, when
    44  a conflicting, concurrently running transaction has already been committed.  Two
    45  transactions conflict when both transactions:
    46  
    47  - write values to the same scalar predicate of the same node (e.g both
    48    attempting to set a particular node's `address` predicate); or
    49  - write to a singular `uid` predicate of the same node (changes to `[uid]` predicates can be concurrently written); or
    50  - write a value that conflicts on an index for a predicate with `@upsert` set in the schema (see [upserts]({{< relref "howto/index.md#upserts">}})).
    51  
    52  When a transaction is aborted, all its changes are discarded.  Transactions can be manually aborted.
    53  
    54  ## Go
    55  
    56  [![GoDoc](https://godoc.org/github.com/dgraph-io/dgo?status.svg)](https://godoc.org/github.com/dgraph-io/dgo)
    57  
    58  The Go client communicates with the server on the gRPC port (default value 9080).
    59  
    60  The client can be obtained in the usual way via `go get`:
    61  
    62  ```sh
    63  # Requires at least Go 1.11
    64  export GO111MODULE=on
    65  go get -u -v github.com/dgraph-io/dgo/v2
    66  ```
    67  
    68  The full [GoDoc](https://godoc.org/github.com/dgraph-io/dgo) contains
    69  documentation for the client API along with examples showing how to use it.
    70  
    71  ### Create the client
    72  
    73  To create a client, dial a connection to Dgraph's external gRPC port (typically
    74  9080). The following code snippet shows just one connection. You can connect to multiple Dgraph Alphas to distribute the workload evenly.
    75  
    76  ```go
    77  func newClient() *dgo.Dgraph {
    78  	// Dial a gRPC connection. The address to dial to can be configured when
    79  	// setting up the dgraph cluster.
    80  	d, err := grpc.Dial("localhost:9080", grpc.WithInsecure())
    81  	if err != nil {
    82  		log.Fatal(err)
    83  	}
    84  
    85  	return dgo.NewDgraphClient(
    86  		api.NewDgraphClient(d),
    87  	)
    88  }
    89  ```
    90  
    91  The client can be configured to use gRPC compression:
    92  
    93  ```go
    94  func newClient() *dgo.Dgraph {
    95  	// Dial a gRPC connection. The address to dial to can be configured when
    96  	// setting up the dgraph cluster.
    97  	dialOpts := append([]grpc.DialOption{},
    98  		grpc.WithInsecure(),
    99  		grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name)))
   100  	d, err := grpc.Dial("localhost:9080", dialOpts...)
   101  
   102  	if err != nil {
   103  		log.Fatal(err)
   104  	}
   105  
   106  	return dgo.NewDgraphClient(
   107  		api.NewDgraphClient(d),
   108  	)
   109  }
   110  
   111  ```
   112  
   113  ### Alter the database
   114  
   115  To set the schema, set it on a `api.Operation` object, and pass it down to
   116  the `Alter` method.
   117  
   118  ```go
   119  func setup(c *dgo.Dgraph) {
   120  	// Install a schema into dgraph. Accounts have a `name` and a `balance`.
   121  	err := c.Alter(context.Background(), &api.Operation{
   122  		Schema: `
   123  			name: string @index(term) .
   124  			balance: int .
   125  		`,
   126  	})
   127  }
   128  ```
   129  
   130  `api.Operation` contains other fields as well, including drop predicate and drop
   131  all. Drop all is useful if you wish to discard all the data, and start from a
   132  clean slate, without bringing the instance down.
   133  
   134  ```go
   135  	// Drop all data including schema from the dgraph instance. This is useful
   136  	// for small examples such as this, since it puts dgraph into a clean
   137  	// state.
   138  	err := c.Alter(context.Background(), &api.Operation{DropOp: api.Operation_ALL})
   139  ```
   140  
   141  The old way to send a drop all operation is still supported but will be eventually
   142  deprecated. It's shown below for reference.
   143  
   144  ```go
   145  	// Drop all data including schema from the dgraph instance. This is useful
   146  	// for small examples such as this, since it puts dgraph into a clean
   147  	// state.
   148  	err := c.Alter(context.Background(), &api.Operation{DropAll: true})
   149  ```
   150  
   151  Starting with version 1.1, `api.Operation` also supports a drop data operation.
   152  This operation drops all the data but preserves the schema. This is useful when
   153  the schema is large and needs to be reused, such as in between unit tests.
   154  
   155  ```go
   156  	// Drop all data including schema from the dgraph instance. This is useful
   157  	// for small examples such as this, since it puts dgraph into a clean
   158  	// state.
   159  	err := c.Alter(context.Background(), &api.Operation{DropOp: api.Operation_DATA})
   160  ```
   161  
   162  ### Create a transaction
   163  
   164  Dgraph supports running distributed ACID transactions. To create a
   165  transaction, just call `c.NewTxn()`. This operation incurs no network call.
   166  Typically, you'd also want to call a `defer txn.Discard()` to let it
   167  automatically rollback in case of errors. Calling `Discard` after `Commit` would
   168  be a no-op.
   169  
   170  ```go
   171  func runTxn(c *dgo.Dgraph) {
   172  	txn := c.NewTxn()
   173  	defer txn.Discard()
   174  	...
   175  }
   176  ```
   177  
   178  #### Read-Only Transactions
   179  
   180  Read-only transactions can be created by calling `c.NewReadOnlyTxn()`. Read-only
   181  transactions are useful to increase read speed because they can circumvent the
   182  usual consensus protocol. Read-only transactions cannot contain mutations and
   183  trying to call `txn.Commit()` will result in an error. Calling `txn.Discard()`
   184  will be a no-op.
   185  
   186  Read-only queries can optionally be set as best-effort. Using this flag will ask
   187  the Dgraph Alpha to try to get timestamps from memory on a best-effort basis to
   188  reduce the number of outbound requests to Zero. This may yield improved
   189  latencies in read-bound workloads where linearizable reads are not strictly
   190  needed.
   191  
   192  ### Run a query
   193  
   194  You can run a query by calling `txn.Query`. The response would contain a `JSON`
   195  field, which has the JSON encoded result. You can unmarshal it into Go struct
   196  via `json.Unmarshal`.
   197  
   198  ```go
   199  	// Query the balance for Alice and Bob.
   200  	const q = `
   201  		{
   202  			all(func: anyofterms(name, "Alice Bob")) {
   203  				uid
   204  				balance
   205  			}
   206  		}
   207  	`
   208  	resp, err := txn.Query(context.Background(), q)
   209  	if err != nil {
   210  		log.Fatal(err)
   211  	}
   212  
   213  	// After we get the balances, we have to decode them into structs so that
   214  	// we can manipulate the data.
   215  	var decode struct {
   216  		All []struct {
   217  			Uid     string
   218  			Balance int
   219  		}
   220  	}
   221  	if err := json.Unmarshal(resp.GetJson(), &decode); err != nil {
   222  		log.Fatal(err)
   223  	}
   224  ```
   225  
   226  ### Run a mutation
   227  
   228  `txn.Mutate` would run the mutation. It takes in a `api.Mutation` object,
   229  which provides two main ways to set data: JSON and RDF N-Quad. You can choose
   230  whichever way is convenient.
   231  
   232  To use JSON, use the fields SetJson and DeleteJson, which accept a string
   233  representing the nodes to be added or removed respectively (either as a JSON map
   234  or a list). To use RDF, use the fields SetNquads and DeleteNquads, which accept
   235  a string representing the valid RDF triples (one per line) to added or removed
   236  respectively. This protobuf object also contains the Set and Del fields which
   237  accept a list of RDF triples that have already been parsed into our internal
   238  format. As such, these fields are mainly used internally and users should use
   239  the SetNquads and DeleteNquads instead if they are planning on using RDF.
   240  
   241  We're going to continue using JSON. You could modify the Go structs parsed from
   242  the query, and marshal them back into JSON.
   243  
   244  ```go
   245  	// Move $5 between the two accounts.
   246  	decode.All[0].Bal += 5
   247  	decode.All[1].Bal -= 5
   248  
   249  	out, err := json.Marshal(decode.All)
   250  	if err != nil {
   251  		log.Fatal(err)
   252  	}
   253  
   254  	_, err := txn.Mutate(context.Background(), &api.Mutation{SetJson: out})
   255  ```
   256  
   257  Sometimes, you only want to commit mutation, without querying anything further.
   258  In such cases, you can use a `CommitNow` field in `api.Mutation` to
   259  indicate that the mutation must be immediately committed.
   260  
   261  ### Commit the transaction
   262  
   263  Once all the queries and mutations are done, you can commit the transaction. It
   264  returns an error in case the transaction could not be committed.
   265  
   266  ```go
   267  	// Finally, we can commit the transactions. An error will be returned if
   268  	// other transactions running concurrently modify the same data that was
   269  	// modified in this transaction. It is up to the library user to retry
   270  	// transactions when they fail.
   271  
   272  	err := txn.Commit(context.Background())
   273  ```
   274  
   275  ### Complete Example
   276  
   277  This is an example from the [GoDoc](https://godoc.org/github.com/dgraph-io/dgo). It shows how to to create a Node with name Alice, while also creating her relationships with other nodes. Note `loc` predicate is of type `geo` and can be easily marshalled and unmarshalled into a Go struct. More such examples are present as part of the GoDoc.
   278  
   279  ```go
   280  type School struct {
   281  	Name string `json:"name,omitempty"`
   282  	DType []string `json:"dgraph.type,omitempty"`
   283  }
   284  
   285  type loc struct {
   286  	Type   string    `json:"type,omitempty"`
   287  	Coords []float64 `json:"coordinates,omitempty"`
   288  }
   289  
   290  // If omitempty is not set, then edges with empty values (0 for int/float, "" for string, false
   291  // for bool) would be created for values not specified explicitly.
   292  
   293  type Person struct {
   294  		Uid      string     `json:"uid,omitempty"`
   295  		Name     string     `json:"name,omitempty"`
   296  		Age      int        `json:"age,omitempty"`
   297  		Dob      *time.Time `json:"dob,omitempty"`
   298  		Married  bool       `json:"married,omitempty"`
   299  		Raw      []byte     `json:"raw_bytes,omitempty"`
   300  		Friends  []Person   `json:"friend,omitempty"`
   301  		Location loc        `json:"loc,omitempty"`
   302  		School   []School   `json:"school,omitempty"`
   303  		DType    []string   `json:"dgraph.type,omitempty"`
   304  }
   305  
   306  conn, err := grpc.Dial("127.0.0.1:9080", grpc.WithInsecure())
   307  if err != nil {
   308  	log.Fatal("While trying to dial gRPC")
   309  }
   310  defer conn.Close()
   311  
   312  dc := api.NewDgraphClient(conn)
   313  dg := dgo.NewDgraphClient(dc)
   314  
   315  op := &api.Operation{}
   316  op.Schema = `
   317  	name: string @index(exact) .
   318  	age: int .
   319  	married: bool .
   320  	loc: geo .
   321  	dob: datetime .
   322  
   323  type Person {
   324    name
   325    age
   326    dob
   327    married
   328    raw
   329    friends
   330    loc
   331    school
   332   }
   333  
   334  type Loc {
   335    type
   336    coords
   337   }
   338  
   339  type Institution {
   340    name
   341   }
   342  
   343  `
   344  
   345  ctx := context.Background()
   346  err = dg.Alter(ctx, op)
   347  if err != nil {
   348  	log.Fatal(err)
   349  }
   350  
   351  dob := time.Date(1980, 01, 01, 23, 0, 0, 0, time.UTC)
   352  // While setting an object if a struct has a Uid then its properties in the graph are updated
   353  // else a new node is created.
   354  // In the example below new nodes for Alice, Bob and Charlie and school are created (since they
   355  // dont have a Uid).
   356  p := Person{
   357      Uid:     "_:alice",
   358  	Name:    "Alice",
   359  	DType: []string{"Person"},
   360  	Age:     26,
   361  	Married: true,
   362  	Location: loc{
   363  		Type:   "Point",
   364  		Coords: []float64{1.1, 2},
   365  	},
   366  	Dob: &dob,
   367  	Raw: []byte("raw_bytes"),
   368  	Friends: []Person{{
   369  		Name: "Bob",
   370  		Age:  24,
   371  	}, {
   372  		Name: "Charlie",
   373  		Age:  29,
   374  	}},
   375  	School: []School{{
   376  		Name: "Crown Public School",
   377  	}},
   378  }
   379  
   380  mu := &api.Mutation{
   381  	CommitNow: true,
   382  }
   383  pb, err := json.Marshal(p)
   384  if err != nil {
   385  	log.Fatal(err)
   386  }
   387  
   388  mu.SetJson = pb
   389  assigned, err := dg.NewTxn().Mutate(ctx, mu)
   390  if err != nil {
   391  	log.Fatal(err)
   392  }
   393  
   394  // Assigned uids for nodes which were created would be returned in the resp.AssignedUids map.
   395  variables := map[string]string{"$id": assigned.Uids["alice"]}
   396  q := `query Me($id: string){
   397  	me(func: uid($id)) {
   398  		name
   399  		dob
   400  		age
   401  		loc
   402  		raw_bytes
   403  		married
   404  		dgraph.type
   405  		friend @filter(eq(name, "Bob")){
   406  			name
   407  			age
   408  			dgraph.type
   409  		}
   410  		school {
   411  			name
   412  			dgraph.type
   413  		}
   414  	}
   415  }`
   416  
   417  resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
   418  if err != nil {
   419  	log.Fatal(err)
   420  }
   421  
   422  type Root struct {
   423  	Me []Person `json:"me"`
   424  }
   425  
   426  var r Root
   427  err = json.Unmarshal(resp.Json, &r)
   428  if err != nil {
   429  	log.Fatal(err)
   430  }
   431  // fmt.Printf("Me: %+v\n", r.Me)
   432  // R.Me would be same as the person that we set above.
   433  
   434  fmt.Println(string(resp.Json))
   435  // Output: {"me":[{"name":"Alice","dob":"1980-01-01T23:00:00Z","age":26,"loc":{"type":"Point","coordinates":[1.1,2]},"raw_bytes":"cmF3X2J5dGVz","married":true,"dgraph.type":["Person"],"friend":[{"name":"Bob","age":24,"dgraph.type":["Person"]}],"school":[{"name":"Crown Public School","dgraph.type":["Institution"]}]}]}
   436  
   437  
   438  ```
   439  
   440  
   441  ## Java
   442  
   443  The official Java client [can be found here](https://github.com/dgraph-io/dgraph4j)
   444  and it fully supports Dgraph v1.0.x. Follow the instructions in the
   445  [README](https://github.com/dgraph-io/dgraph4j#readme)
   446  to get it up and running.
   447  
   448  We also have a [DgraphJavaSample] project, which contains an end-to-end
   449  working example of how to use the Java client.
   450  
   451  [DgraphJavaSample]:https://github.com/dgraph-io/dgraph4j/tree/master/samples/DgraphJavaSample
   452  
   453  ## JavaScript
   454  
   455  The official JavaScript client [can be found here](https://github.com/dgraph-io/dgraph-js)
   456  and it fully supports Dgraph v1.0.x. Follow the instructions in the
   457  [README](https://github.com/dgraph-io/dgraph-js#readme) to get it up and running.
   458  
   459  We also have a [simple example](https://github.com/dgraph-io/dgraph-js/tree/master/examples/simple)
   460  project, which contains an end-to-end working example of how to use the JavaScript client,
   461  for Node.js >= v6.
   462  
   463  ## Python
   464  
   465  The official Python client [can be found here](https://github.com/dgraph-io/pydgraph)
   466  and it fully supports Dgraph v1.0.x and Python versions >= 2.7 and >= 3.5. Follow the
   467  instructions in the [README](https://github.com/dgraph-io/pydgraph#readme) to get it
   468  up and running.
   469  
   470  We also have a [simple example](https://github.com/dgraph-io/pydgraph/tree/master/examples/simple)
   471  project, which contains an end-to-end working example of how to use the Python client.
   472  
   473  ## Unofficial Dgraph Clients
   474  
   475  {{% notice "note" %}}
   476  These third-party clients are contributed by the community and are not officially supported by Dgraph.
   477  {{% /notice %}}
   478  
   479  ### C\#
   480  
   481  - https://github.com/AlexandreDaSilva/DgraphNet
   482  - https://github.com/MichaelJCompton/Dgraph-dotnet
   483  
   484  ### Dart
   485  
   486  - https://github.com/katutz/dgraph
   487  
   488  ### Elixir
   489  
   490  - https://github.com/liveforeverx/dlex
   491  - https://github.com/ospaarmann/exdgraph
   492  
   493  ### JavaScript
   494  
   495  - https://github.com/ashokvishwakarma/dgraph-orm
   496  - https://github.com/gverse/gverse
   497  
   498  ### Rust
   499  
   500  - https://github.com/Swoorup/dgraph-rs
   501  
   502  ## Raw HTTP
   503  
   504  {{% notice "warning" %}}
   505  Raw HTTP needs more chops to use than our language clients. We wrote this guide to help you build a Dgraph client in a new language.
   506  {{% /notice %}}
   507  
   508  It's also possible to interact with Dgraph directly via its HTTP endpoints.
   509  This allows clients to be built for languages that don't have access to a
   510  working gRPC implementation.
   511  
   512  In the examples shown here, regular command line tools such as `curl` and
   513  [`jq`](https://stedolan.github.io/jq/) are used. However, the real intention
   514  here is to show other programmers how they could implement a client in their
   515  language on top of the HTTP API. For an example of how to build a client on top
   516  of gRPC, refer to the implementation of the Go client.
   517  
   518  Similar to the Go client example, we use a bank account transfer example.
   519  
   520  ### Create the Client
   521  
   522  A client built on top of the HTTP API will need to track three pieces of state
   523  for each transaction.
   524  
   525  1. A start timestamp (`start_ts`). This uniquely identifies a transaction,
   526     and doesn't change over the transaction lifecycle.
   527  
   528  2. The set of keys modified by the transaction (`keys`). This aids in
   529     transaction conflict detection.
   530  
   531       Every mutation would send back a new set of keys. The client must merge them
   532       with the existing set. Optionally, a client can de-dup these keys while
   533       merging.
   534  
   535  3. The set of predicates modified by the transaction (`preds`). This aids in
   536     predicate move detection.
   537  
   538       Every mutation would send back a new set of preds. The client must merge them
   539       with the existing set. Optionally, a client can de-dup these keys while
   540       merging.
   541  
   542  ### Alter the database
   543  
   544  The `/alter` endpoint is used to create or change the schema. Here, the
   545  predicate `name` is the name of an account. It's indexed so that we can look up
   546  accounts based on their name.
   547  
   548  ```sh
   549  $ curl -X POST localhost:8080/alter -d \
   550  'name: string @index(term) .
   551  type Person {
   552     name
   553  }'
   554  ```
   555  
   556  If all goes well, the response should be `{"code":"Success","message":"Done"}`.
   557  
   558  Other operations can be performed via the `/alter` endpoint as well. A specific
   559  predicate or the entire database can be dropped.
   560  
   561  To drop the predicate `name`:
   562  
   563  ```sh
   564  $ curl -X POST localhost:8080/alter -d '{"drop_attr": "name"}'
   565  ```
   566  
   567  To drop the type `Film`:
   568  ```sh
   569  $ curl -X POST localhost:8080/alter -d '{"drop_op": "TYPE", "drop_value": "Film"}'
   570  ```
   571  
   572  To drop all data and schema:
   573  ```sh
   574  $ curl -X POST localhost:8080/alter -d '{"drop_all": true}'
   575  ```
   576  
   577  To drop all data only (keep schema):
   578  ```sh
   579  $ curl -X POST localhost:8080/alter -d '{"drop_op": "DATA"}'
   580  ```
   581  
   582  ### Start a transaction
   583  
   584  Assume some initial accounts with balances have been populated. We now want to
   585  transfer money from one account to the other. This is done in four steps:
   586  
   587  1. Create a new transaction.
   588  
   589  1. Inside the transaction, run a query to determine the current balances.
   590  
   591  2. Perform a mutation to update the balances.
   592  
   593  3. Commit the transaction.
   594  
   595  Starting a transaction doesn't require any interaction with Dgraph itself.
   596  Some state needs to be set up for the transaction to use. The `start_ts`
   597  can initially be set to 0. `keys` can start as an empty set.
   598  
   599  **For both query and mutation if the `start_ts` is provided as a path parameter,
   600  then the operation is performed as part of the ongoing transaction. Otherwise, a
   601  new transaction is initiated.**
   602  
   603  ### Run a query
   604  
   605  To query the database, the `/query` endpoint is used. Remember to set the `Content-Type` header
   606  to `application/graphql+-` in order to ensure that the body of the request is correctly parsed.
   607  
   608  To get the balances for both accounts:
   609  
   610  ```sh
   611  $ curl -H "Content-Type: application/graphql+-" -X POST localhost:8080/query -d $'
   612  {
   613    balances(func: anyofterms(name, "Alice Bob")) {
   614      uid
   615      name
   616      balance
   617    }
   618  }' | jq
   619  
   620  ```
   621  
   622  The result should look like this:
   623  
   624  ```json
   625  {
   626    "data": {
   627      "balances": [
   628        {
   629          "uid": "0x1",
   630          "name": "Alice",
   631          "balance": "100"
   632        },
   633        {
   634          "uid": "0x2",
   635          "name": "Bob",
   636          "balance": "70"
   637        }
   638      ]
   639    },
   640    "extensions": {
   641      "server_latency": {
   642        "parsing_ns": 70494,
   643        "processing_ns": 697140,
   644        "encoding_ns": 1560151
   645      },
   646      "txn": {
   647        "start_ts": 4,
   648      }
   649    }
   650  }
   651  ```
   652  
   653  Notice that along with the query result under the `data` field is additional
   654  data in the `extensions -> txn` field. This data will have to be tracked by the
   655  client.
   656  
   657  For queries, there is a `start_ts` in the response. This `start_ts` will need to
   658  be used in all subsequent interactions with Dgraph for this transaction, and so
   659  should become part of the transaction state.
   660  
   661  ### Run a Mutation
   662  
   663  Now that we have the current balances, we need to send a mutation to Dgraph
   664  with the updated balances. If Bob transfers $10 to Alice, then the RDFs to send
   665  are:
   666  
   667  ```
   668  <0x1> <balance> "110" .
   669  <0x1> <dgraph.type> "Balance" .
   670  <0x2> <balance> "60" .
   671  <0x2> <dgraph.type> "Balance" .
   672  ```
   673  
   674  Note that we have to refer to the Alice and Bob nodes by UID in the RDF format.
   675  
   676  We now send the mutations via the `/mutate` endpoint. We need to provide our
   677  transaction start timestamp as a path parameter, so that Dgraph knows which
   678  transaction the mutation should be part of. We also need to set `Content-Type`
   679  header to `application/rdf` in order to specify that mutation is written in
   680  rdf format.
   681  
   682  ```sh
   683  $ curl -H "Content-Type: application/rdf" -X POST localhost:8080/mutate?startTs=4 -d $'
   684  {
   685    set {
   686      <0x1> <balance> "110" .
   687      <0x1> <dgraph.type> "Balance" .
   688      <0x2> <balance> "60" .
   689      <0x2> <dgraph.type> "Balance" .
   690    }
   691  }
   692  ' | jq
   693  ```
   694  
   695  The result:
   696  
   697  ```json
   698  {
   699    "data": {
   700      "code": "Success",
   701      "message": "Done",
   702      "uids": {}
   703    },
   704    "extensions": {
   705      "server_latency": {
   706        "parsing_ns": 50901,
   707        "processing_ns": 14631082
   708      },
   709      "txn": {
   710        "start_ts": 4,
   711        "keys": [
   712          "2ahy9oh4s9csc",
   713          "3ekeez23q5149"
   714        ],
   715        "preds": [
   716          "1-balance"
   717        ]
   718      }
   719    }
   720  }
   721  ```
   722  
   723  We get some `keys`. These should be added to the set of `keys` stored in the
   724  transaction state. We also get some `preds`, which should be added to the set of
   725  `preds` stored in the transaction state.
   726  
   727  ### Committing the transaction
   728  
   729  {{% notice "note" %}}
   730  It's possible to commit immediately after a mutation is made (without requiring
   731  to use the `/commit` endpoint as explained in this section). To do this, add
   732  the parameter `commitNow` in the URL `/mutate?commitNow=true`.
   733  {{% /notice %}}
   734  
   735  Finally, we can commit the transaction using the `/commit` endpoint. We need the
   736  `start_ts` we've been using for the transaction along with the `keys` and the
   737  `preds`. If we had performed multiple mutations in the transaction instead of
   738  just one, then the keys and preds provided during the commit would be the union
   739  of all keys and preds returned in the responses from the `/mutate` endpoint.
   740  
   741  The `preds` field is used to abort the transaction in cases where some of the
   742  predicates are moved. This field is not required and the `/commit` endpoint also
   743  accepts the old format, which was a single array of keys.
   744  
   745  ```sh
   746  $ curl -X POST localhost:8080/commit?startTs=4 -d $'
   747  {
   748    "keys": [
   749  		"2ahy9oh4s9csc",
   750  		"3ekeez23q5149"
   751  	],
   752    "preds": [
   753      "1-balance"
   754  	]
   755  }' | jq
   756  ```
   757  
   758  The result:
   759  
   760  ```json
   761  {
   762    "data": {
   763      "code": "Success",
   764      "message": "Done"
   765    },
   766    "extensions": {
   767      "txn": {
   768        "start_ts": 4,
   769        "commit_ts": 5
   770      }
   771    }
   772  }
   773  ```
   774  The transaction is now complete.
   775  
   776  If another client were to perform another transaction concurrently affecting
   777  the same keys, then it's possible that the transaction would *not* be
   778  successful.  This is indicated in the response when the commit is attempted.
   779  
   780  ```json
   781  {
   782    "errors": [
   783      {
   784        "code": "Error",
   785        "message": "Transaction has been aborted. Please retry."
   786      }
   787    ]
   788  }
   789  ```
   790  
   791  In this case, it should be up to the user of the client to decide if they wish
   792  to retry the transaction.
   793  
   794  ### Aborting the transaction
   795  To abort a transaction, use the same `/commit` endpoint with the `abort=true` parameter
   796  while specifying the `startTs` value for the transaction.
   797  
   798  ```sh
   799  $ curl -X POST "localhost:8080/commit?startTs=4&abort=true" | jq
   800  ```
   801  
   802  The result:
   803  
   804  ```json
   805  {
   806    "code": "Success",
   807    "message": "Done"
   808  }
   809  ```
   810  
   811  ### Compression via HTTP
   812  
   813  Dgraph supports gzip-compressed requests to and from Dgraph Alphas for `/query`, `/mutate`, and `/alter`.
   814  
   815  Compressed requests: To send compressed requests, set the HTTP request header
   816  `Content-Encoding: gzip` along with the gzip-compressed payload.
   817  
   818  Compressed responses: To receive gzipped responses, set the HTTP request header
   819  `Accept-Encoding: gzip` and Alpha will return gzipped responses.
   820  
   821  Example of a compressed request via curl:
   822  
   823  ```sh
   824  $ curl -X POST \
   825    -H 'Content-Encoding: gzip' \
   826    -H "Content-Type: application/rdf" \
   827    localhost:8080/mutate?commitNow=true --data-binary @mutation.gz
   828  ```
   829  
   830  Example of a compressed request via curl:
   831  
   832  ```sh
   833  $ curl -X POST \
   834    -H 'Accept-Encoding: gzip' \
   835    -H "Content-Type: application/graphql+-" \
   836    localhost:8080/query -d $'schema {}' | gzip --decompress
   837  ```
   838  
   839  Example of a compressed request and response via curl:
   840  
   841  ```sh
   842  $ zcat query.gz # query.gz is gzipped compressed
   843  {
   844    all(func: anyofterms(name, "Alice Bob")) {
   845      uid
   846      balance
   847    }
   848  }
   849  ```
   850  
   851  ```sh
   852  $ curl -X POST \
   853    -H 'Content-Encoding: gzip' \
   854    -H 'Accept-Encoding: gzip' \
   855    -H "Content-Type: application/graphql+-" \
   856    localhost:8080/query --data-binary @query.gz | gzip --decompress
   857  ```
   858  
   859  {{% notice "note" %}}
   860  Curl has a `--compressed` option that automatically requests for a compressed response (`Accept-Encoding` header) and decompresses the compressed response.
   861  
   862  ```sh
   863  $ curl -X POST --compressed -H "Content-Type: application/graphql+-" localhost:8080/query -d $'schema {}'
   864  ```
   865  {{% /notice %}}
   866  
   867  ### Health Check and Alpha Info
   868  
   869  `/health` returns HTTP status code 200 if the worker is running, HTTP 503 otherwise.
   870  The body of the response contains information about the running alpha and its version.
   871  
   872  ```sh
   873  $ curl localhost:8080/health
   874  ```
   875  
   876  ```json
   877  {
   878    "version": "v1.1.0",
   879    "instance": "alpha",
   880    "uptime": 1928423
   881  }
   882  ```
   883  
   884  Here, `uptime` is in nanoseconds (type `time.Duration` in Go).
   885  
   886  ### Run a query in JSON format
   887  
   888  The 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]({{< relref "query-language/index.md#graphql-variables" >}}) with the HTTP API.
   889  
   890  This query:
   891  
   892  ```
   893  {
   894    balances(func: anyofterms(name, "Alice Bob")) {
   895      uid
   896      name
   897      balance
   898    }
   899  }
   900  ```
   901  
   902  Should be escaped to this:
   903  
   904  ```sh
   905  curl -H "Content-Type: application/json" localhost:8080/query -XPOST -d '{
   906      "query": "{\n balances(func: anyofterms(name, \"Alice Bob\")) {\n uid\n name\n balance\n }\n }"
   907  }' | python -m json.tool | jq
   908  ```