Skip to content

Commit e0beb37

Browse files
authored
add browser note in js sdk (#143)
1 parent c82f81e commit e0beb37

File tree

1 file changed

+303
-0
lines changed

1 file changed

+303
-0
lines changed

dgraph/sdks/javascript.mdx

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,3 +424,306 @@ meta.add("auth-token", "mySuperSecret")
424424

425425
await dgraphClient.alter(op, meta)
426426
```
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

Comments
 (0)