diff --git a/dgraph/sdks/javascript.mdx b/dgraph/sdks/javascript.mdx index 8088e034..9e75dfff 100644 --- a/dgraph/sdks/javascript.mdx +++ b/dgraph/sdks/javascript.mdx @@ -424,3 +424,306 @@ meta.add("auth-token", "mySuperSecret") await dgraphClient.alter(op, meta) ``` + +## Browser support + + + The official Dgraph JavaScript gRPC client is designed for Node.js + environments and doesn't officially support browser usage due to gRPC-web + limitations and bundling complexities. However, you can achieve **most** of + the same capabilities in browsers using Dgraph's HTTP API with standard + `fetch` requests. + + + + If you only need basic CRUD operations and don't require admin endpoints (like + schema alterations or dropping data), consider using Dgraph's GraphQL API + instead, which is designed for client-side usage and provides better security + boundaries. + + + + We don't recommend connecting directly to Dgraph from browser applications as + this could expose your database credentials and connection details to end + users. Consider using a backend API as a proxy instead. + + +### Node.js gRPC vs browser HTTP API + +Below are side-by-side examples showing how to perform common operations using +both the Node.js gRPC client and browser-compatible HTTP requests. + +#### Creating a connection + +**Node.js (gRPC):** + +```js +const dgraph = require("dgraph-js") +const grpc = require("grpc") + +const clientStub = new dgraph.DgraphClientStub( + "localhost:9080", + grpc.credentials.createInsecure(), +) +const dgraphClient = new dgraph.DgraphClient(clientStub) +``` + +**Browser (HTTP):** + +```js +const DGRAPH_HTTP_URL = "http://localhost:8080" + +// Test connection to Dgraph +const response = await fetch(`${DGRAPH_HTTP_URL}/health`) +if (!response.ok) { + throw new Error(`Cannot connect to Dgraph: ${response.status}`) +} +console.log("Connected to Dgraph successfully") +``` + +#### Setting schema + +**Node.js (gRPC):** + +```js +const schema = "name: string @index(exact) ." +const op = new dgraph.Operation() +op.setSchema(schema) +await dgraphClient.alter(op) +``` + +**Browser (HTTP):** + +```js +const schema = "name: string @index(exact) ." + +await fetch(`${DGRAPH_HTTP_URL}/alter`, { + method: "POST", + headers: { "Content-Type": "application/rdf" }, + body: schema, +}) +``` + +#### Running queries + +**Node.js (gRPC):** + +```js +const query = `query all($a: string) { + all(func: eq(name, $a)) { + name + } +}` +const vars = { $a: "Alice" } +const res = await dgraphClient.newTxn().queryWithVars(query, vars) +const data = res.getJson() +``` + +**Browser (HTTP):** + +```js +const query = `query all($a: string) { + all(func: eq(name, $a)) { + name + } +}` +const vars = { $a: "Alice" } + +const response = await fetch(`${DGRAPH_HTTP_URL}/query`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ query, variables: vars }), +}) +const data = await response.json() +``` + +#### Running mutations + +**Node.js (gRPC):** + +```js +const txn = dgraphClient.newTxn() +try { + const p = { name: "Alice", age: 26 } + const mu = new dgraph.Mutation() + mu.setSetJson(p) + mu.setCommitNow(true) + await txn.mutate(mu) +} finally { + await txn.discard() +} +``` + +**Browser (HTTP):** + +```js +const p = { name: "Alice", age: 26 } + +await fetch(`${DGRAPH_HTTP_URL}/mutate?commitNow=true`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ set: [p] }), +}) +``` + +#### Upsert operations + +**Node.js (gRPC):** + +```js +const query = `query { + user as var(func: eq(email, "wrong_email@dgraph.io")) +}` + +const mu = new dgraph.Mutation() +mu.setSetNquads(`uid(user) "correct_email@dgraph.io" .`) + +const req = new dgraph.Request() +req.setQuery(query) +req.setMutationsList([mu]) +req.setCommitNow(true) + +await dgraphClient.newTxn().doRequest(req) +``` + +**Browser (HTTP):** + +```js +const query = `query { + user as var(func: eq(email, "wrong_email@dgraph.io")) +}` + +await fetch(`${DGRAPH_HTTP_URL}/mutate?commitNow=true`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + query: query, + set: [{ uid: "uid(user)", email: "correct_email@dgraph.io" }], + }), +}) +``` + +#### Conditional upserts + +**Node.js (gRPC):** + +```js +const query = `query { + user as var(func: eq(email, "wrong_email@dgraph.io")) +}` + +const mu = new dgraph.Mutation() +mu.setSetNquads(`uid(user) "correct_email@dgraph.io" .`) +mu.setCond(`@if(eq(len(user), 1))`) + +const req = new dgraph.Request() +req.setQuery(query) +req.addMutations(mu) +req.setCommitNow(true) + +await dgraphClient.newTxn().doRequest(req) +``` + +**Browser (HTTP):** + +```js +const query = `query { + user as var(func: eq(email, "wrong_email@dgraph.io")) +}` + +await fetch(`${DGRAPH_HTTP_URL}/mutate?commitNow=true`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + query: query, + mutations: [ + { + set: [{ uid: "uid(user)", email: "correct_email@dgraph.io" }], + cond: "@if(eq(len(user), 1))", + }, + ], + }), +}) +``` + +#### Drop all data + +**Node.js (gRPC):** + +```js +const op = new dgraph.Operation() +op.setDropAll(true) +await dgraphClient.alter(op) +``` + +**Browser (HTTP):** + +```js +await fetch(`${DGRAPH_HTTP_URL}/alter`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ drop_all: true }), +}) +``` + +#### Authentication + +**Node.js (gRPC):** + +```js +const meta = new grpc.Metadata() +meta.add("auth-token", "mySuperSecret") +await dgraphClient.alter(op, meta) +``` + +**Browser (HTTP):** + +```js +await fetch(`${DGRAPH_HTTP_URL}/alter`, { + method: "POST", + headers: { + "Content-Type": "application/rdf", + "auth-token": "mySuperSecret", + }, + body: schema, +}) +``` + +### Browser-specific considerations + +#### Connection strings + +For convenience, you can parse connection strings similar to database URLs: + +```js +function parseDgraphUrl(connectionString) { + if (connectionString.startsWith("http")) { + return { url: connectionString, headers: {} } + } + + // Handle dgraph://user:pass@host:port format + const url = new URL(connectionString.replace("dgraph://", "https://")) + const headers = {} + + if (url.username && url.password) { + headers["Authorization"] = + `Basic ${btoa(`${url.username}:${url.password}`)}` + } + + return { + url: `http://${url.hostname}:${url.port || 8080}`, + headers, + } +} + +// Usage +const { url, headers } = parseDgraphUrl("dgraph://user:pass@localhost:8080") +const DGRAPH_HTTP_URL = url +``` + +### Limitations of HTTP API + +- **No streaming**: HTTP doesn't support gRPC streaming capabilities +- **Transaction isolation**: HTTP requests are stateless; use upserts for + consistency +- **Performance**: Higher overhead compared to persistent gRPC connections