@@ -424,3 +424,306 @@ meta.add("auth-token", "mySuperSecret")
424
424
425
425
await dgraphClient .alter (op, meta)
426
426
```
427
+
428
+ ## Browser support
429
+
430
+ <Note >
431
+ The official Dgraph JavaScript gRPC client is designed for Node.js
432
+ environments and doesn't officially support browser usage due to gRPC-web
433
+ limitations and bundling complexities. However, you can achieve ** most** of
434
+ the same capabilities in browsers using Dgraph's HTTP API with standard
435
+ ` fetch ` requests.
436
+ </Note >
437
+
438
+ <Tip >
439
+ If you only need basic CRUD operations and don't require admin endpoints (like
440
+ schema alterations or dropping data), consider using Dgraph's GraphQL API
441
+ instead, which is designed for client-side usage and provides better security
442
+ boundaries.
443
+ </Tip >
444
+
445
+ <Warning >
446
+ We don't recommend connecting directly to Dgraph from browser applications as
447
+ this could expose your database credentials and connection details to end
448
+ users. Consider using a backend API as a proxy instead.
449
+ </Warning >
450
+
451
+ ### Node.js gRPC vs browser HTTP API
452
+
453
+ Below are side-by-side examples showing how to perform common operations using
454
+ both the Node.js gRPC client and browser-compatible HTTP requests.
455
+
456
+ #### Creating a connection
457
+
458
+ ** Node.js (gRPC):**
459
+
460
+ ``` js
461
+ const dgraph = require (" dgraph-js" )
462
+ const grpc = require (" grpc" )
463
+
464
+ const clientStub = new dgraph.DgraphClientStub (
465
+ " localhost:9080" ,
466
+ grpc .credentials .createInsecure (),
467
+ )
468
+ const dgraphClient = new dgraph.DgraphClient (clientStub)
469
+ ```
470
+
471
+ ** Browser (HTTP):**
472
+
473
+ ``` js
474
+ const DGRAPH_HTTP_URL = " http://localhost:8080"
475
+
476
+ // Test connection to Dgraph
477
+ const response = await fetch (` ${ DGRAPH_HTTP_URL } /health` )
478
+ if (! response .ok ) {
479
+ throw new Error (` Cannot connect to Dgraph: ${ response .status } ` )
480
+ }
481
+ console .log (" Connected to Dgraph successfully" )
482
+ ```
483
+
484
+ #### Setting schema
485
+
486
+ ** Node.js (gRPC):**
487
+
488
+ ``` js
489
+ const schema = " name: string @index(exact) ."
490
+ const op = new dgraph.Operation ()
491
+ op .setSchema (schema)
492
+ await dgraphClient .alter (op)
493
+ ```
494
+
495
+ ** Browser (HTTP):**
496
+
497
+ ``` js
498
+ const schema = " name: string @index(exact) ."
499
+
500
+ await fetch (` ${ DGRAPH_HTTP_URL } /alter` , {
501
+ method: " POST" ,
502
+ headers: { " Content-Type" : " application/rdf" },
503
+ body: schema,
504
+ })
505
+ ```
506
+
507
+ #### Running queries
508
+
509
+ ** Node.js (gRPC):**
510
+
511
+ ``` js
512
+ const query = ` query all($a: string) {
513
+ all(func: eq(name, $a)) {
514
+ name
515
+ }
516
+ }`
517
+ const vars = { $a: " Alice" }
518
+ const res = await dgraphClient .newTxn ().queryWithVars (query, vars)
519
+ const data = res .getJson ()
520
+ ```
521
+
522
+ ** Browser (HTTP):**
523
+
524
+ ``` js
525
+ const query = ` query all($a: string) {
526
+ all(func: eq(name, $a)) {
527
+ name
528
+ }
529
+ }`
530
+ const vars = { $a: " Alice" }
531
+
532
+ const response = await fetch (` ${ DGRAPH_HTTP_URL } /query` , {
533
+ method: " POST" ,
534
+ headers: { " Content-Type" : " application/json" },
535
+ body: JSON .stringify ({ query, variables: vars }),
536
+ })
537
+ const data = await response .json ()
538
+ ```
539
+
540
+ #### Running mutations
541
+
542
+ ** Node.js (gRPC):**
543
+
544
+ ``` js
545
+ const txn = dgraphClient .newTxn ()
546
+ try {
547
+ const p = { name: " Alice" , age: 26 }
548
+ const mu = new dgraph.Mutation ()
549
+ mu .setSetJson (p)
550
+ mu .setCommitNow (true )
551
+ await txn .mutate (mu)
552
+ } finally {
553
+ await txn .discard ()
554
+ }
555
+ ```
556
+
557
+ ** Browser (HTTP):**
558
+
559
+ ``` js
560
+ const p = { name: " Alice" , age: 26 }
561
+
562
+ await fetch (` ${ DGRAPH_HTTP_URL } /mutate?commitNow=true` , {
563
+ method: " POST" ,
564
+ headers: { " Content-Type" : " application/json" },
565
+ body: JSON .stringify ({ set: [p] }),
566
+ })
567
+ ```
568
+
569
+ #### Upsert operations
570
+
571
+ ** Node.js (gRPC):**
572
+
573
+ ``` js
574
+ const query = ` query {
575
+ user as var(func: eq(email, "[email protected] "))
576
+ }`
577
+
578
+ const mu = new dgraph.Mutation ()
579
+ mu .
setSetNquads (
` uid(user) <email> "[email protected] " .` )
580
+
581
+ const req = new dgraph.Request ()
582
+ req .setQuery (query)
583
+ req .setMutationsList ([mu])
584
+ req .setCommitNow (true )
585
+
586
+ await dgraphClient .newTxn ().doRequest (req)
587
+ ```
588
+
589
+ ** Browser (HTTP):**
590
+
591
+ ``` js
592
+ const query = ` query {
593
+ user as var(func: eq(email, "[email protected] "))
594
+ }`
595
+
596
+ await fetch (` ${ DGRAPH_HTTP_URL } /mutate?commitNow=true` , {
597
+ method: " POST" ,
598
+ headers: { " Content-Type" : " application/json" },
599
+ body: JSON .stringify ({
600
+ query: query,
601
+ set
: [{ uid
: " uid(user)" , email
: " [email protected] " }],
602
+ }),
603
+ })
604
+ ```
605
+
606
+ #### Conditional upserts
607
+
608
+ ** Node.js (gRPC):**
609
+
610
+ ``` js
611
+ const query = ` query {
612
+ user as var(func: eq(email, "[email protected] "))
613
+ }`
614
+
615
+ const mu = new dgraph.Mutation ()
616
+ mu .
setSetNquads (
` uid(user) <email> "[email protected] " .` )
617
+ mu .setCond (` @if(eq(len(user), 1))` )
618
+
619
+ const req = new dgraph.Request ()
620
+ req .setQuery (query)
621
+ req .addMutations (mu)
622
+ req .setCommitNow (true )
623
+
624
+ await dgraphClient .newTxn ().doRequest (req)
625
+ ```
626
+
627
+ ** Browser (HTTP):**
628
+
629
+ ``` js
630
+ const query = ` query {
631
+ user as var(func: eq(email, "[email protected] "))
632
+ }`
633
+
634
+ await fetch (` ${ DGRAPH_HTTP_URL } /mutate?commitNow=true` , {
635
+ method: " POST" ,
636
+ headers: { " Content-Type" : " application/json" },
637
+ body: JSON .stringify ({
638
+ query: query,
639
+ mutations: [
640
+ {
641
+ set
: [{ uid
: " uid(user)" , email
: " [email protected] " }],
642
+ cond: " @if(eq(len(user), 1))" ,
643
+ },
644
+ ],
645
+ }),
646
+ })
647
+ ```
648
+
649
+ #### Drop all data
650
+
651
+ ** Node.js (gRPC):**
652
+
653
+ ``` js
654
+ const op = new dgraph.Operation ()
655
+ op .setDropAll (true )
656
+ await dgraphClient .alter (op)
657
+ ```
658
+
659
+ ** Browser (HTTP):**
660
+
661
+ ``` js
662
+ await fetch (` ${ DGRAPH_HTTP_URL } /alter` , {
663
+ method: " POST" ,
664
+ headers: { " Content-Type" : " application/json" },
665
+ body: JSON .stringify ({ drop_all: true }),
666
+ })
667
+ ```
668
+
669
+ #### Authentication
670
+
671
+ ** Node.js (gRPC):**
672
+
673
+ ``` js
674
+ const meta = new grpc.Metadata ()
675
+ meta .add (" auth-token" , " mySuperSecret" )
676
+ await dgraphClient .alter (op, meta)
677
+ ```
678
+
679
+ ** Browser (HTTP):**
680
+
681
+ ``` js
682
+ await fetch (` ${ DGRAPH_HTTP_URL } /alter` , {
683
+ method: " POST" ,
684
+ headers: {
685
+ " Content-Type" : " application/rdf" ,
686
+ " auth-token" : " mySuperSecret" ,
687
+ },
688
+ body: schema,
689
+ })
690
+ ```
691
+
692
+ ### Browser-specific considerations
693
+
694
+ #### Connection strings
695
+
696
+ For convenience, you can parse connection strings similar to database URLs:
697
+
698
+ ``` js
699
+ function parseDgraphUrl (connectionString ) {
700
+ if (connectionString .startsWith (" http" )) {
701
+ return { url: connectionString, headers: {} }
702
+ }
703
+
704
+ // Handle dgraph://user:pass@host:port format
705
+ const url = new URL (connectionString .replace (" dgraph://" , " https://" ))
706
+ const headers = {}
707
+
708
+ if (url .username && url .password ) {
709
+ headers[" Authorization" ] =
710
+ ` Basic ${ btoa (` ${ url .username } :${ url .password } ` )} `
711
+ }
712
+
713
+ return {
714
+ url: ` http://${ url .hostname } :${ url .port || 8080 } ` ,
715
+ headers,
716
+ }
717
+ }
718
+
719
+ // Usage
720
+ const { url , headers } = parseDgraphUrl (" dgraph://user:pass@localhost:8080" )
721
+ const DGRAPH_HTTP_URL = url
722
+ ```
723
+
724
+ ### Limitations of HTTP API
725
+
726
+ - ** No streaming** : HTTP doesn't support gRPC streaming capabilities
727
+ - ** Transaction isolation** : HTTP requests are stateless; use upserts for
728
+ consistency
729
+ - ** Performance** : Higher overhead compared to persistent gRPC connections
0 commit comments