Skip to content

Commit a992459

Browse files
resolve review comments
1 parent 261c19d commit a992459

File tree

5 files changed

+67
-75
lines changed

5 files changed

+67
-75
lines changed

README.md

Lines changed: 36 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -51,24 +51,38 @@ of using the Dgraph JavaScript client. Follow the instructions in the README of
5151

5252
### Creating a Client
5353

54-
A `DgraphClient` object can be initialised by passing it a list of `DgraphClientStub` clients as
55-
variadic arguments. Connecting to multiple Dgraph servers in the same cluster allows for better
56-
distribution of workload.
54+
#### Connection Strings
5755

58-
The following code snippet shows just one connection.
56+
The dgraph-js supports connecting to a Dgraph cluster using connection strings. Dgraph connections
57+
strings take the form `dgraph://{username:password@}host:port?args`.
5958

60-
```js
61-
const dgraph = require("dgraph-js")
62-
const grpc = require("@grpc/grpc-js")
63-
64-
const clientStub = new dgraph.DgraphClientStub(
65-
// addr: optional, default: "localhost:9080"
66-
"localhost:9080",
67-
// credentials: optional, default: grpc.credentials.createInsecure()
68-
grpc.credentials.createInsecure(),
69-
)
70-
const dgraphClient = new dgraph.DgraphClient(clientStub)
71-
```
59+
`username` and `password` are optional. If username is provided, a password must also be present. If
60+
supplied, these credentials are used to log into a Dgraph cluster through the ACL mechanism.
61+
62+
Valid connection string args:
63+
64+
| Arg | Value | Description |
65+
| ----------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
66+
| apikey | \<key\> | a Dgraph Cloud API Key |
67+
| bearertoken | \<token\> | an access token |
68+
| sslmode | disable \| require \| verify-ca | TLS option, the default is `disable`. If `verify-ca` is set, the TLS certificate configured in the Dgraph cluster must be from a valid certificate authority. |
69+
70+
## Some example connection strings: | Value | Explanation | |
71+
72+
| ----------------------------------------------------------------------------------- | |
73+
dgraph://localhost:9080 | Connect to localhost, no ACL, no TLS | |
74+
dgraph://sally:supersecret@dg.example.com:443?sslmode=verify-ca | Connect to remote server, use ACL
75+
and require TLS and a valid certificate from a CA | |
76+
dgraph://foo-bar.grpc.us-west-2.aws.cloud.dgraph.io:443?sslmode=verify-ca&apikey=\<your-api-connection-key\>
77+
| Connect to a Dgraph Cloud cluster | |
78+
dgraph://foo-bar.grpc.hypermode.com?sslmode=verify-ca&bearertoken=\<some access token\> | Connect to
79+
a Dgraph cluster protected by a secure gateway |
80+
81+
Using the `Open` function with a connection string: // open a connection to an ACL-enabled, non-TLS
82+
cluster and login as groot const {client,closeStub} =
83+
dgraph.Open("dgraph://groot:password@localhost:8090")
84+
85+
````
7286
7387
To facilitate debugging, [debug mode](#debug-mode) can be enabled for a client.
7488
@@ -83,31 +97,12 @@ In order to create a JavaScript client, and make the client login into namespace
8397
```js
8498
const dgraphClientStub = new dgraph.DgraphClientStub("localhost:9080")
8599
await dgraphClientStub.loginIntoNamespace("groot", "password", 123) // where 123 is the namespaceId
86-
```
100+
````
87101

88102
In the example above, the client logs into namespace `123` using username `groot` and password
89103
`password`. Once logged in, the client can perform all the operations allowed to the `groot` user of
90104
namespace `123`.
91105

92-
### Creating a Client for Dgraph Cloud Endpoint
93-
94-
If you want to connect to Dgraph running on your [Dgraph Cloud](https://cloud.dgraph.io) instance,
95-
then all you need is the URL of your Dgraph Cloud endpoint and the API key. You can get a client
96-
using them as follows:
97-
98-
```js
99-
const dgraph = require("dgraph-js")
100-
101-
const clientStub = dgraph.clientStubFromCloudEndpoint(
102-
"https://frozen-mango.eu-central-1.aws.cloud.dgraph.io/graphql",
103-
"<api-key>",
104-
)
105-
const dgraphClient = new dgraph.DgraphClient(clientStub)
106-
```
107-
108-
**Note:** the `clientStubFromSlashGraphQLEndpoint` method is deprecated and will be removed in the
109-
next release. Instead use `clientStubFromCloudEndpoint` method.
110-
111106
### Altering the Database
112107

113108
To set the schema, create an `Operation` object, set the schema and pass it to
@@ -376,27 +371,21 @@ try {
376371

377372
### Cleanup Resources
378373

379-
To cleanup resources, you have to call `DgraphClientStub#close()` individually for all the instances
380-
of `DgraphClientStub`.
374+
To cleanup resources, you have to call `close()`.
381375

382376
```js
383377
const SERVER_ADDR = "localhost:9080"
384378
const SERVER_CREDENTIALS = grpc.credentials.createInsecure()
385379

386-
// Create instances of DgraphClientStub.
387-
const stub1 = new dgraph.DgraphClientStub(SERVER_ADDR, SERVER_CREDENTIALS)
388-
const stub2 = new dgraph.DgraphClientStub(SERVER_ADDR, SERVER_CREDENTIALS)
389-
390-
// Create an instance of DgraphClient.
391-
const dgraphClient = new dgraph.DgraphClient(stub1, stub2)
380+
// Create instances of DgraphClient.
381+
const { client, closeStub } = dgraph.Open("dgraph://groot:password@${SERVER_ADDR}")
392382

393383
// ...
394384
// Use dgraphClient
395385
// ...
396386

397-
// Cleanup resources by closing all client stubs.
398-
stub1.close()
399-
stub2.close()
387+
// Cleanup resources by closing client stubs.
388+
closeStub()
400389
```
401390

402391
### Debug mode

examples/simple/index.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,7 @@ async function queryData(dgraphClient) {
125125
}
126126

127127
async function main() {
128-
const dgraphClientStub = newClientStub()
129-
const dgraphClient = newClient(dgraphClientStub)
128+
const { dgraphClient, closeStub } = dgraph.Open()
130129
await dropAll(dgraphClient)
131130
await setSchema(dgraphClient)
132131
await createData(dgraphClient)
@@ -137,7 +136,7 @@ async function main() {
137136
await queryData(dgraphClient)
138137

139138
// Close the client stub.
140-
dgraphClientStub.close()
139+
closeStub()
141140
}
142141

143142
main()

src/client.ts

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
*/
55

66
import * as grpc from "@grpc/grpc-js"
7-
import * as url from "url"
8-
import * as querystring from "querystring"
97

108
import * as messages from "../generated/api_pb"
119

@@ -159,9 +157,10 @@ function addBearerTokenToCredentials(
159157
return grpc.credentials.combineChannelCredentials(baseCreds, metaCreds)
160158
}
161159

162-
export async function Open(connStr: string): Promise<DgraphClient> {
163-
const parsedUrl = url.parse(connStr)
164-
160+
export async function Open(
161+
connStr: string,
162+
): Promise<{ client: DgraphClient; closeStub: () => void }> {
163+
const parsedUrl = new URL(connStr)
165164
if (parsedUrl.protocol !== dgraphScheme) {
166165
throw new Error("Invalid scheme: must start with dgraph://")
167166
}
@@ -175,11 +174,11 @@ export async function Open(connStr: string): Promise<DgraphClient> {
175174
throw new Error("Invalid connection string: port required")
176175
}
177176

177+
// Parse query parameters using searchParams
178178
const queryParams: Record<string, string> = {}
179-
if (parsedUrl.query) {
180-
const parsedQuery = querystring.parse(parsedUrl.query)
181-
Object.entries(parsedQuery).forEach(([key, value]) => {
182-
queryParams[key] = Array.isArray(value) ? value[0] : value
179+
if (parsedUrl.searchParams) {
180+
parsedUrl.searchParams.forEach((value, key) => {
181+
queryParams[key] = value
183182
})
184183
}
185184

@@ -218,18 +217,20 @@ export async function Open(connStr: string): Promise<DgraphClient> {
218217

219218
const clientStub = new DgraphClientStub(`${host}:${port}`, credentials)
220219

221-
if (parsedUrl.auth) {
222-
const [username, password] = parsedUrl.auth.split(":")
223-
if (!password) {
220+
if (parsedUrl.username != "") {
221+
if (parsedUrl.password === "") {
224222
throw new Error("Invalid connection string: password required when username is provided")
225-
}
226-
227-
try {
228-
await clientStub.login(username, password)
229-
} catch (err) {
230-
throw new Error(`Failed to sign in user: ${err.message}`)
223+
} else {
224+
try {
225+
await clientStub.login(parsedUrl.username, parsedUrl.password)
226+
} catch (err) {
227+
throw new Error(`Failed to sign in user: ${err.message}`)
228+
}
231229
}
232230
}
233231

234-
return new DgraphClient(clientStub)
232+
return {
233+
client: new DgraphClient(clientStub),
234+
closeStub: () => clientStub.close(),
235+
}
235236
}

src/clientStubFromSlash.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ export function clientStubFromSlashGraphQLEndpoint(graphqlEndpoint: string, apiK
1717
return clientStubFromCloudEndpoint(graphqlEndpoint, apiKey)
1818
}
1919

20+
/**
21+
* @deprecated
22+
* Please use {@link Open} instead.
23+
*/
2024
export function clientStubFromCloudEndpoint(graphqlEndpoint: string, apiKey: string) {
2125
const url = new Url(graphqlEndpoint)
2226
const urlParts = url.host.split(".")

tests/integration/connect.spec.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { SERVER_ADDR } from "../helper"
1010
describe("open function", () => {
1111
it("should connect with authentication and execute a query", async () => {
1212
const url = `dgraph://groot:password@${SERVER_ADDR}`
13-
const client = await dgraph.Open(url)
13+
const { client, closeStub } = await dgraph.Open(url)
1414
const query = `
1515
{
1616
me(func: uid(1)) {
@@ -25,6 +25,7 @@ describe("open function", () => {
2525
expect(response).not.toBeNull()
2626
const parsedJson = response.getJson() // No need for JSON.parse
2727
expect(parsedJson.me[0].uid).toBe("0x1")
28+
closeStub()
2829
})
2930

3031
it("should throw an error for invalid scheme", async () => {
@@ -35,14 +36,12 @@ describe("open function", () => {
3536
})
3637

3738
it("should throw an error for missing hostname", async () => {
38-
const invalidUrl = `dgraph://:${SERVER_ADDR.split(":")[1]}`
39-
await expect(async () => dgraph.Open(invalidUrl)).rejects.toThrowError(
40-
"Invalid connection string: hostname required",
41-
)
39+
const invalidUrl = `dgraph://:9081`
40+
await expect(async () => dgraph.Open(invalidUrl)).rejects.toThrowError("Invalid URL")
4241
})
4342

4443
it("should throw an error for missing port", async () => {
45-
const invalidUrl = `dgraph://${SERVER_ADDR.split(":")[0]}`
44+
const invalidUrl = `dgraph://localhost`
4645
await expect(async () => await dgraph.Open(invalidUrl)).rejects.toThrowError(
4746
"Invalid connection string: port required",
4847
)

0 commit comments

Comments
 (0)