github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/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 [](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: string 325 age: int 326 dob: string 327 married: bool 328 raw: string 329 friends: [uid] 330 loc: [uid] 331 school: [uid] 332 } 333 334 type Loc { 335 type: string 336 coords: float 337 } 338 339 type Institution { 340 name: string 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 Age: 26, 360 Married: true, 361 Location: loc{ 362 Type: "Point", 363 Coords: []float64{1.1, 2}, 364 }, 365 Dob: &dob, 366 Raw: []byte("raw_bytes"), 367 Friends: []Person{{ 368 Name: "Bob", 369 Age: 24, 370 }, { 371 Name: "Charlie", 372 Age: 29, 373 }}, 374 School: []School{{ 375 Name: "Crown Public School", 376 }}, 377 } 378 379 mu := &api.Mutation{ 380 CommitNow: true, 381 } 382 pb, err := json.Marshal(p) 383 if err != nil { 384 log.Fatal(err) 385 } 386 387 mu.SetJson = pb 388 assigned, err := dg.NewTxn().Mutate(ctx, mu) 389 if err != nil { 390 log.Fatal(err) 391 } 392 393 // Assigned uids for nodes which were created would be returned in the resp.AssignedUids map. 394 variables := map[string]string{"$id": assigned.Uids["alice"]} 395 q := `query Me($id: string){ 396 me(func: uid($id)) { 397 name 398 dob 399 age 400 loc 401 raw_bytes 402 married 403 dgraph.type 404 friend @filter(eq(name, "Bob")){ 405 name 406 age 407 dgraph.type 408 } 409 school { 410 name 411 dgraph.type 412 } 413 } 414 }` 415 416 resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables) 417 if err != nil { 418 log.Fatal(err) 419 } 420 421 type Root struct { 422 Me []Person `json:"me"` 423 } 424 425 var r Root 426 err = json.Unmarshal(resp.Json, &r) 427 if err != nil { 428 log.Fatal(err) 429 } 430 // fmt.Printf("Me: %+v\n", r.Me) 431 // R.Me would be same as the person that we set above. 432 433 fmt.Println(string(resp.Json)) 434 // 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"]}]}]} 435 436 437 ``` 438 439 440 ## Java 441 442 The official Java client [can be found here](https://github.com/dgraph-io/dgraph4j) 443 and it fully supports Dgraph v1.0.x. Follow the instructions in the 444 [README](https://github.com/dgraph-io/dgraph4j#readme) 445 to get it up and running. 446 447 We also have a [DgraphJavaSample] project, which contains an end-to-end 448 working example of how to use the Java client. 449 450 [DgraphJavaSample]:https://github.com/dgraph-io/dgraph4j/tree/master/samples/DgraphJavaSample 451 452 ## JavaScript 453 454 The official JavaScript client [can be found here](https://github.com/dgraph-io/dgraph-js) 455 and it fully supports Dgraph v1.0.x. Follow the instructions in the 456 [README](https://github.com/dgraph-io/dgraph-js#readme) to get it up and running. 457 458 We also have a [simple example](https://github.com/dgraph-io/dgraph-js/tree/master/examples/simple) 459 project, which contains an end-to-end working example of how to use the JavaScript client, 460 for Node.js >= v6. 461 462 ## Python 463 464 The official Python client [can be found here](https://github.com/dgraph-io/pydgraph) 465 and it fully supports Dgraph v1.0.x and Python versions >= 2.7 and >= 3.5. Follow the 466 instructions in the [README](https://github.com/dgraph-io/pydgraph#readme) to get it 467 up and running. 468 469 We also have a [simple example](https://github.com/dgraph-io/pydgraph/tree/master/examples/simple) 470 project, which contains an end-to-end working example of how to use the Python client. 471 472 ## Unofficial Dgraph Clients 473 474 {{% notice "note" %}} 475 These third-party clients are contributed by the community and are not officially supported by Dgraph. 476 {{% /notice %}} 477 478 ### C\# 479 480 - https://github.com/AlexandreDaSilva/DgraphNet 481 - https://github.com/MichaelJCompton/Dgraph-dotnet 482 483 ### Dart 484 485 - https://github.com/katutz/dgraph 486 487 ### Elixir 488 489 - https://github.com/liveforeverx/dlex 490 - https://github.com/ospaarmann/exdgraph 491 492 ### Rust 493 494 - https://github.com/Swoorup/dgraph-rs 495 496 ## Raw HTTP 497 498 {{% notice "warning" %}} 499 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. 500 {{% /notice %}} 501 502 It's also possible to interact with Dgraph directly via its HTTP endpoints. 503 This allows clients to be built for languages that don't have access to a 504 working gRPC implementation. 505 506 In the examples shown here, regular command line tools such as `curl` and 507 [`jq`](https://stedolan.github.io/jq/) are used. However, the real intention 508 here is to show other programmers how they could implement a client in their 509 language on top of the HTTP API. For an example of how to build a client on top 510 of gRPC, refer to the implementation of the Go client. 511 512 Similar to the Go client example, we use a bank account transfer example. 513 514 ### Create the Client 515 516 A client built on top of the HTTP API will need to track three pieces of state 517 for each transaction. 518 519 1. A start timestamp (`start_ts`). This uniquely identifies a transaction, 520 and doesn't change over the transaction lifecycle. 521 522 2. The set of keys modified by the transaction (`keys`). This aids in 523 transaction conflict detection. 524 525 Every mutation would send back a new set of keys. The client must merge them 526 with the existing set. Optionally, a client can de-dup these keys while 527 merging. 528 529 3. The set of predicates modified by the transaction (`preds`). This aids in 530 predicate move detection. 531 532 Every mutation would send back a new set of preds. The client must merge them 533 with the existing set. Optionally, a client can de-dup these keys while 534 merging. 535 536 ### Alter the database 537 538 The `/alter` endpoint is used to create or change the schema. Here, the 539 predicate `name` is the name of an account. It's indexed so that we can look up 540 accounts based on their name. 541 542 ```sh 543 $ curl -X POST localhost:8080/alter -d 'name: string @index(term) .' 544 ``` 545 546 If all goes well, the response should be `{"code":"Success","message":"Done"}`. 547 548 Other operations can be performed via the `/alter` endpoint as well. A specific 549 predicate or the entire database can be dropped. 550 551 To drop the predicate `name`: 552 ```sh 553 $ curl -X POST localhost:8080/alter -d '{"drop_attr": "name"}' 554 ``` 555 556 To drop the type `Film`: 557 ```sh 558 $ curl -X POST localhost:8080/alter -d '{"drop_op": "TYPE", "drop_value": "Film"}' 559 ``` 560 561 To drop all data and schema: 562 ```sh 563 $ curl -X POST localhost:8080/alter -d '{"drop_all": true}' 564 ``` 565 566 To drop all data only (keep schema): 567 ```sh 568 $ curl -X POST localhost:8080/alter -d '{"drop_op": "DATA"}' 569 ``` 570 571 ### Start a transaction 572 573 Assume some initial accounts with balances have been populated. We now want to 574 transfer money from one account to the other. This is done in four steps: 575 576 1. Create a new transaction. 577 578 1. Inside the transaction, run a query to determine the current balances. 579 580 2. Perform a mutation to update the balances. 581 582 3. Commit the transaction. 583 584 Starting a transaction doesn't require any interaction with Dgraph itself. 585 Some state needs to be set up for the transaction to use. The `start_ts` 586 can initially be set to 0. `keys` can start as an empty set. 587 588 **For both query and mutation if the `start_ts` is provided as a path parameter, 589 then the operation is performed as part of the ongoing transaction. Otherwise, a 590 new transaction is initiated.** 591 592 ### Run a query 593 594 To query the database, the `/query` endpoint is used. Remember to set the `Content-Type` header 595 to `application/graphql+-` in order to ensure that the body of the request is correctly parsed. 596 597 To get the balances for both accounts: 598 599 ```sh 600 $ curl -H "Content-Type: application/graphql+-" -X POST localhost:8080/query -d $' 601 { 602 balances(func: anyofterms(name, "Alice Bob")) { 603 uid 604 name 605 balance 606 } 607 }' | jq 608 609 ``` 610 611 The result should look like this: 612 613 ```json 614 { 615 "data": { 616 "balances": [ 617 { 618 "uid": "0x1", 619 "name": "Alice", 620 "balance": "100" 621 }, 622 { 623 "uid": "0x2", 624 "name": "Bob", 625 "balance": "70" 626 } 627 ] 628 }, 629 "extensions": { 630 "server_latency": { 631 "parsing_ns": 70494, 632 "processing_ns": 697140, 633 "encoding_ns": 1560151 634 }, 635 "txn": { 636 "start_ts": 4, 637 } 638 } 639 } 640 ``` 641 642 Notice that along with the query result under the `data` field is additional 643 data in the `extensions -> txn` field. This data will have to be tracked by the 644 client. 645 646 For queries, there is a `start_ts` in the response. This `start_ts` will need to 647 be used in all subsequent interactions with Dgraph for this transaction, and so 648 should become part of the transaction state. 649 650 ### Run a Mutation 651 652 Now that we have the current balances, we need to send a mutation to Dgraph 653 with the updated balances. If Bob transfers $10 to Alice, then the RDFs to send 654 are: 655 656 ``` 657 <0x1> <balance> "110" . 658 <0x2> <balance> "60" . 659 ``` 660 661 Note that we have to refer to the Alice and Bob nodes by UID in the RDF format. 662 663 We now send the mutations via the `/mutate` endpoint. We need to provide our 664 transaction start timestamp as a path parameter, so that Dgraph knows which 665 transaction the mutation should be part of. We also need to set `Content-Type` 666 header to `application/rdf` in order to specify that mutation is written in 667 rdf format. 668 669 ```sh 670 $ curl -H "Content-Type: application/rdf" -X POST localhost:8080/mutate?startTs=4 -d $' 671 { 672 set { 673 <0x1> <balance> "110" . 674 <0x2> <balance> "60" . 675 } 676 } 677 ' | jq 678 ``` 679 680 The result: 681 682 ```json 683 { 684 "data": { 685 "code": "Success", 686 "message": "Done", 687 "uids": {} 688 }, 689 "extensions": { 690 "server_latency": { 691 "parsing_ns": 50901, 692 "processing_ns": 14631082 693 }, 694 "txn": { 695 "start_ts": 4, 696 "keys": [ 697 "2ahy9oh4s9csc", 698 "3ekeez23q5149" 699 ], 700 "preds": [ 701 "1-balance" 702 ] 703 } 704 } 705 } 706 ``` 707 708 We get some `keys`. These should be added to the set of `keys` stored in the 709 transaction state. We also get some `preds`, which should be added to the set of 710 `preds` stored in the transaction state. 711 712 ### Committing the transaction 713 714 {{% notice "note" %}} 715 It's possible to commit immediately after a mutation is made (without requiring 716 to use the `/commit` endpoint as explained in this section). To do this, add 717 the parameter `commitNow` in the URL `/mutate?commitNow=true`. 718 {{% /notice %}} 719 720 Finally, we can commit the transaction using the `/commit` endpoint. We need the 721 `start_ts` we've been using for the transaction along with the `keys` and the 722 `preds`. If we had performed multiple mutations in the transaction instead of 723 just one, then the keys and preds provided during the commit would be the union 724 of all keys and preds returned in the responses from the `/mutate` endpoint. 725 726 The `preds` field is used to abort the transaction in cases where some of the 727 predicates are moved. This field is not required and the `/commit` endpoint also 728 accepts the old format, which was a single array of keys. 729 730 ```sh 731 $ curl -X POST localhost:8080/commit?startTs=4 -d $' 732 { 733 "keys": [ 734 "2ahy9oh4s9csc", 735 "3ekeez23q5149" 736 ], 737 "preds": [ 738 "1-balance" 739 ] 740 }' | jq 741 ``` 742 743 The result: 744 745 ```json 746 { 747 "data": { 748 "code": "Success", 749 "message": "Done" 750 }, 751 "extensions": { 752 "txn": { 753 "start_ts": 4, 754 "commit_ts": 5 755 } 756 } 757 } 758 ``` 759 The transaction is now complete. 760 761 If another client were to perform another transaction concurrently affecting 762 the same keys, then it's possible that the transaction would *not* be 763 successful. This is indicated in the response when the commit is attempted. 764 765 ```json 766 { 767 "errors": [ 768 { 769 "code": "Error", 770 "message": "Transaction has been aborted. Please retry." 771 } 772 ] 773 } 774 ``` 775 776 In this case, it should be up to the user of the client to decide if they wish 777 to retry the transaction. 778 779 ### Aborting the transaction 780 To abort a transaction, use the same `/commit` endpoint with the `abort=true` parameter 781 while specifying the `startTs` value for the transaction. 782 783 ```sh 784 $ curl -X POST "localhost:8080/commit?startTs=4&abort=true" | jq 785 ``` 786 787 The result: 788 789 ```json 790 { 791 "code": "Success", 792 "message": "Done" 793 } 794 ``` 795 796 ### Compression via HTTP 797 798 Dgraph supports gzip-compressed requests to and from Dgraph Alphas for `/query`, `/mutate`, and `/alter`. 799 800 Compressed requests: To send compressed requests, set the HTTP request header 801 `Content-Encoding: gzip` along with the gzip-compressed payload. 802 803 Compressed responses: To receive gzipped responses, set the HTTP request header 804 `Accept-Encoding: gzip` and Alpha will return gzipped responses. 805 806 Example of a compressed request via curl: 807 808 ```sh 809 $ curl -X POST \ 810 -H 'Content-Encoding: gzip' \ 811 -H "Content-Type: application/rdf" \ 812 localhost:8080/mutate?commitNow=true --data-binary @mutation.gz 813 ``` 814 815 Example of a compressed request via curl: 816 817 ```sh 818 $ curl -X POST \ 819 -H 'Accept-Encoding: gzip' \ 820 -H "Content-Type: application/graphql+-" \ 821 localhost:8080/query -d $'schema {}' | gzip --decompress 822 ``` 823 824 Example of a compressed request and response via curl: 825 826 ```sh 827 $ zcat query.gz # query.gz is gzipped compressed 828 { 829 all(func: anyofterms(name, "Alice Bob")) { 830 uid 831 balance 832 } 833 } 834 ``` 835 836 ```sh 837 $ curl -X POST \ 838 -H 'Content-Encoding: gzip' \ 839 -H 'Accept-Encoding: gzip' \ 840 -H "Content-Type: application/graphql+-" \ 841 localhost:8080/query --data-binary @query.gz | gzip --decompress 842 ``` 843 844 {{% notice "note" %}} 845 Curl has a `--compressed` option that automatically requests for a compressed response (`Accept-Encoding` header) and decompresses the compressed response. 846 847 ```sh 848 $ curl -X POST --compressed -H "Content-Type: application/graphql+-" localhost:8080/query -d $'schema {}' 849 ``` 850 {{% /notice %}} 851 852 ### Health Check and Alpha Info 853 854 `/health` returns HTTP status code 200 if the worker is running, HTTP 503 otherwise. 855 The body of the response contains information about the running alpha and its version. 856 857 ```sh 858 $ curl localhost:8080/health 859 ``` 860 861 ```json 862 { 863 "version": "v1.1.0", 864 "instance": "alpha", 865 "uptime": 1928423 866 } 867 ``` 868 869 Here, `uptime` is in nanoseconds (type `time.Duration` in Go). 870 871 ### Run a query in JSON format 872 873 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. 874 875 This query: 876 877 ``` 878 { 879 balances(func: anyofterms(name, "Alice Bob")) { 880 uid 881 name 882 balance 883 } 884 } 885 ``` 886 887 Should be escaped to this: 888 889 ```sh 890 curl -H "Content-Type: application/json" localhost:8080/query -XPOST -d '{ 891 "query": "{\n balances(func: anyofterms(name, \"Alice Bob\")) {\n uid\n name\n balance\n }\n }" 892 }' | python -m json.tool | jq 893 ```