@cubicweb/client
Advanced tools
Comparing version 3.0.0-alpha.15 to 3.0.0
@@ -0,1 +1,2 @@ | ||
import type { Authenticator } from "../Authenticator.js"; | ||
import { RawSchema } from "../schema/raw/Schema.js"; | ||
@@ -6,2 +7,5 @@ import { RQLBinary } from "./binary/RQLBinary.js"; | ||
import { TransactionResult } from "./transaction/TransactionResult.js"; | ||
interface ApiOptions { | ||
authenticator?: Authenticator; | ||
} | ||
/** | ||
@@ -71,2 +75,3 @@ * Type representing valid final values to use as parameters in a RQL query. | ||
private _binaryApiUrl; | ||
private _authenticator?; | ||
/** | ||
@@ -82,3 +87,3 @@ * Class used to handle requests to the CubicWeb API. | ||
*/ | ||
constructor(apiUrl: string); | ||
constructor(apiUrl: string, options: ApiOptions); | ||
get apiUrl(): string; | ||
@@ -134,4 +139,24 @@ private getApiRoute; | ||
private handleUserErrors; | ||
/** | ||
* Behaves the same as `fetchAPI` but forbids null responses. | ||
* If this function detects a null response from the API, | ||
* the promise will be rejected with a 500 error code. | ||
* | ||
* @param input The API route to use | ||
* @param init Additional request parameters | ||
* @returns A promise with the non-null fetched result | ||
*/ | ||
private nonNullFetchApi; | ||
/** | ||
* Sends a request to the given API route with the `Content-Type` header set and waits for a response. | ||
* The returned promise will be rejected if the API returns HTTP error codes. | ||
* The rejected promise will contain an `ApiErrorResponse` object. | ||
* | ||
* @param input The API route to use | ||
* @param init Additional request parameters | ||
* @returns A promise with the fetched result | ||
*/ | ||
private fetchApi; | ||
} | ||
export {}; | ||
//# sourceMappingURL=Api.d.ts.map |
@@ -21,2 +21,3 @@ import { ValidationError } from "../errors.js"; | ||
_binaryApiUrl; | ||
_authenticator; | ||
/** | ||
@@ -32,3 +33,3 @@ * Class used to handle requests to the CubicWeb API. | ||
*/ | ||
constructor(apiUrl) { | ||
constructor(apiUrl, options) { | ||
this._apiUrl = apiUrl; | ||
@@ -41,2 +42,3 @@ this._rqlApiUrl = this.getApiRoute("rql"); | ||
this._binaryApiUrl = this.getApiRoute("binary"); | ||
this._authenticator = options.authenticator; | ||
} | ||
@@ -55,5 +57,4 @@ get apiUrl() { | ||
async schema() { | ||
return nonNullFetchApi(this._schemaApiUrl, { | ||
return this.nonNullFetchApi(this._schemaApiUrl, { | ||
method: "GET", | ||
credentials: "include", | ||
}); | ||
@@ -70,3 +71,3 @@ } | ||
try { | ||
await fetchApi(this._loginApiUrl, { | ||
await this.fetchApi(this._loginApiUrl, { | ||
method: "POST", | ||
@@ -77,3 +78,2 @@ body: JSON.stringify({ | ||
}), | ||
credentials: "include", | ||
}); | ||
@@ -92,5 +92,4 @@ return true; | ||
async logout() { | ||
await fetchApi(this._logoutApiUrl, { | ||
await this.fetchApi(this._logoutApiUrl, { | ||
method: "POST", | ||
credentials: "include", | ||
}); | ||
@@ -104,5 +103,4 @@ } | ||
async currentUser() { | ||
return await nonNullFetchApi(this._currentUserApiUrl, { | ||
return await this.nonNullFetchApi(this._currentUserApiUrl, { | ||
method: "GET", | ||
credentials: "include", | ||
}); | ||
@@ -122,5 +120,4 @@ } | ||
}); | ||
return await nonNullFetchApi(this._binaryApiUrl + params, { | ||
return await this.nonNullFetchApi(this._binaryApiUrl + params, { | ||
method: "GET", | ||
credentials: "include", | ||
}); | ||
@@ -164,5 +161,4 @@ } | ||
}); | ||
const resultSets = await nonNullFetchApi(this._rqlApiUrl, { | ||
const resultSets = await this.nonNullFetchApi(this._rqlApiUrl, { | ||
method: "POST", | ||
credentials: "include", | ||
body: formData, | ||
@@ -173,5 +169,4 @@ }); | ||
async jsonTransaction(transaction) { | ||
const resultSets = await nonNullFetchApi(this._rqlApiUrl, { | ||
const resultSets = await this.nonNullFetchApi(this._rqlApiUrl, { | ||
method: "POST", | ||
credentials: "include", | ||
body: JSON.stringify(this.getTransactionParams(transaction)), | ||
@@ -195,79 +190,84 @@ }); | ||
} | ||
} | ||
/** | ||
* Behaves the same as `fetchAPI` but forbids null responses. | ||
* If this function detects a null response from the API, | ||
* the promise will be rejected with a 500 error code. | ||
* | ||
* @param input The API route to use | ||
* @param init Additional request parameters | ||
* @returns A promise with the non-null fetched result | ||
*/ | ||
async function nonNullFetchApi(input, init) { | ||
const result = await fetchApi(input, init); | ||
if (result == null) { | ||
const error = { | ||
status: 500, | ||
title: "Unexpected null response", | ||
message: "Response was null but a value was expected", | ||
}; | ||
throw error; | ||
} | ||
return result; | ||
} | ||
/** | ||
* Sends a request to the given API route with the `Content-Type` header set and waits for a response. | ||
* The returned promise will be rejected if the API returns HTTP error codes. | ||
* The rejected promise will contain an `ApiErrorResponse` object. | ||
* | ||
* @param input The API route to use | ||
* @param init Additional request parameters | ||
* @returns A promise with the fetched result | ||
*/ | ||
async function fetchApi(input, init) { | ||
let headers = init?.headers; | ||
if (init?.method && init.method !== "GET") { | ||
headers = { | ||
// CSRF custom header necessary for POST requests | ||
"X-Client-Name": "XMLHttpRequest", | ||
}; | ||
// Browsers will automatically set the multipart content type | ||
// with the right boundary if the body is FormData | ||
if (!(init.body instanceof FormData)) { | ||
headers["Content-Type"] = "application/json;charset=UTF-8"; | ||
/** | ||
* Behaves the same as `fetchAPI` but forbids null responses. | ||
* If this function detects a null response from the API, | ||
* the promise will be rejected with a 500 error code. | ||
* | ||
* @param input The API route to use | ||
* @param init Additional request parameters | ||
* @returns A promise with the non-null fetched result | ||
*/ | ||
async nonNullFetchApi(url, init) { | ||
const result = await this.fetchApi(url, init); | ||
if (result == null) { | ||
const error = { | ||
status: 500, | ||
title: "Unexpected null response", | ||
message: "Response was null but a value was expected", | ||
}; | ||
throw error; | ||
} | ||
headers = { | ||
...headers, | ||
...init?.headers, | ||
}; | ||
return result; | ||
} | ||
const response = await fetch(input, { | ||
...init, | ||
headers, | ||
}); | ||
const status = response.status; | ||
if (status >= 200 && status < 300) { | ||
if (status === 204) { | ||
return null; | ||
/** | ||
* Sends a request to the given API route with the `Content-Type` header set and waits for a response. | ||
* The returned promise will be rejected if the API returns HTTP error codes. | ||
* The rejected promise will contain an `ApiErrorResponse` object. | ||
* | ||
* @param input The API route to use | ||
* @param init Additional request parameters | ||
* @returns A promise with the fetched result | ||
*/ | ||
async fetchApi(url, init) { | ||
const headers = new Headers(init.headers); | ||
// Add custom header used as CSRF protection | ||
// note: it is only necessary for non GET requests but can also be useful | ||
// while debugging. | ||
if (!headers.has("X-Client-Name")) { | ||
headers.append("X-Client-Name", "XMLHttpRequest"); | ||
} | ||
try { | ||
return await response.json(); | ||
// Add a "Content-Type" header whenever a body is passed. | ||
// The header might already have been set (either by the caller of this | ||
// function or by and encoder) | ||
if (init.body && | ||
!headers.has("Content-Type") && | ||
!(init.body instanceof FormData)) { | ||
headers.append("Content-Type", "application/json;charset=UTF-8"); | ||
} | ||
catch (e) { | ||
console.error(e); | ||
return null; | ||
init.headers = headers; | ||
// Authenticate request | ||
if (this._authenticator) { | ||
const authenticatedRequest = await this._authenticator.authenticate(url, init); | ||
url = authenticatedRequest.url; | ||
init = authenticatedRequest.init; | ||
} | ||
} | ||
else { | ||
let json; | ||
try { | ||
json = await response.json(); | ||
// Execute request | ||
const response = await fetch(url, init); | ||
// Parse response body and handle errors | ||
const status = response.status; | ||
if (status >= 200 && status < 300) { | ||
if (status === 204) { | ||
return null; | ||
} | ||
try { | ||
return await response.json(); | ||
} | ||
catch (e) { | ||
console.error(e); | ||
return null; | ||
} | ||
} | ||
catch (e) { | ||
console.error(e); | ||
throw { status, title: "Error", message: "" }; | ||
else { | ||
let json; | ||
try { | ||
json = await response.json(); | ||
} | ||
catch (e) { | ||
console.error(e); | ||
throw { status, title: "Error", message: "" }; | ||
} | ||
throw { status, ...json }; | ||
} | ||
throw { status, ...json }; | ||
} | ||
} | ||
//# sourceMappingURL=Api.js.map |
@@ -0,1 +1,2 @@ | ||
import { Authenticator } from "../Authenticator.js"; | ||
import { Schema } from "../schema/classes/Schema.js"; | ||
@@ -6,2 +7,5 @@ import { RQLQueryParams, CurrentUser } from "./Api.js"; | ||
import { TransactionResult } from "./transaction/TransactionResult.js"; | ||
export interface ClientOptions { | ||
authenticator?: Authenticator; | ||
} | ||
/** | ||
@@ -21,3 +25,3 @@ * Class used to communicate with a CubicWeb instance's API. | ||
*/ | ||
constructor(apiUrl: string); | ||
constructor(apiUrl: string, options?: ClientOptions); | ||
get apiUrl(): string; | ||
@@ -24,0 +28,0 @@ /** |
@@ -19,4 +19,4 @@ import { Schema } from "../schema/classes/Schema.js"; | ||
*/ | ||
constructor(apiUrl) { | ||
this.api = new Api(apiUrl); | ||
constructor(apiUrl, options) { | ||
this.api = new Api(apiUrl, options ?? {}); | ||
} | ||
@@ -23,0 +23,0 @@ get apiUrl() { |
@@ -13,3 +13,3 @@ export * from "./schema/raw/Constraints.js"; | ||
export { ResultSet, ResultSetRow, ResultSetCell } from "./api/ResultSet.js"; | ||
export { default as Client } from "./api/Client.js"; | ||
export { default as Client, ClientOptions } from "./api/Client.js"; | ||
export { Transaction } from "./api/transaction/Transaction.js"; | ||
@@ -20,2 +20,3 @@ export { TransactionResult } from "./api/transaction/TransactionResult.js"; | ||
export { RQLQueryRowRef, RQLQueryCellRef } from "./api/query/references.js"; | ||
export { Authenticator } from "./Authenticator.js"; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -5,3 +5,3 @@ { | ||
"author": "Logilab", | ||
"version": "3.0.0-alpha.15", | ||
"version": "3.0.0", | ||
"license": "LGPL-3.0-or-later", | ||
@@ -33,4 +33,7 @@ "scripts": { | ||
"type": "module", | ||
"exports": "./lib/index.js", | ||
"types": "./lib/index.d.ts" | ||
"exports": { | ||
".": "./lib/index.js", | ||
"./authenticators/SignedRequestAuthenticator": "./lib/api/authenticators/SignedRequestAuthenticator.js", | ||
"./authenticators/CookieAuthenticator": "./lib/api/authenticators/CookieAuthenticator.js" | ||
} | ||
} |
@@ -15,2 +15,3 @@ # @cubicweb/client | ||
@cubicweb/client is available from NPM: | ||
```bash | ||
@@ -33,3 +34,3 @@ # With NPM | ||
```js | ||
const client = new Client("https://example.com/api") | ||
const client = new Client("https://example.com/api"); | ||
``` | ||
@@ -82,11 +83,10 @@ | ||
// Execute a series of request in a transaction | ||
const transaction = new Transaction() | ||
const insertQuery = new RQLQuery(`INSERT Person X: X name "test"`) | ||
transaction.push(insertQuery) | ||
const transaction = new Transaction(); | ||
const insertQuery = new RQLQuery(`INSERT Person X: X name "test"`); | ||
transaction.push(insertQuery); | ||
transaction.push( | ||
new RQLQuery( | ||
`INSERT Person X: X name "test"`, | ||
{ created_eid: insertQuery.cellRef(0, 0) } | ||
) | ||
) | ||
new RQLQuery(`INSERT Person X: X name "test"`, { | ||
created_eid: insertQuery.cellRef(0, 0), | ||
}) | ||
); | ||
client | ||
@@ -129,22 +129,54 @@ .executeTransaction(transaction) | ||
[`SameSite`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#samesite_attribute) | ||
to `None`. | ||
to `None`. | ||
You can use other authenticators if needed. Here is an example relying on the | ||
[`cubicweb-signedrequest`](https://forge.extranet.logilab.fr/cubicweb/cubes/signedrequest) | ||
cube (v3.x): | ||
```typescript | ||
import { Client } from "@cubicweb/client"; | ||
import { SignedRequestAuthenticator } from "@cubicweb/client/authenticators/SignedRequestAuthenticator"; | ||
const authenticator = new SignedRequetAuthenticator({ | ||
id: "<token-id>", | ||
token: "<token>", | ||
}); | ||
const client = new Client(API_URL, { authenticator }); | ||
``` | ||
You can also provide your own authenticator by implementing the `Authenticator` interface: | ||
```typescript | ||
import { Authenticator, Client } from "@cubicweb/client"; | ||
const client = new Client(API_URL, { | ||
authenticator: { | ||
authenticate(info, init) { | ||
const headers = new Headers(init.headers); | ||
headers.append("Authorization", `Basic Zm9vOmJhcg==`); | ||
return { info, init: { ...init, headers } }; | ||
}, | ||
}, | ||
}); | ||
``` | ||
## Using the Schema | ||
This library provides CubicWeb [schema abstraction classes](packages/client/src/schema/Schema.ts). Three classes are available: | ||
* `Schema` - Global handling of the schema. | ||
Can be used to query entities and relations. | ||
* `EntitySchema` - Handling of a single entity type. | ||
Can be used to query relations and metadata about the entity. | ||
* `RelationDefinitionSchema` - Handling of a single relation. | ||
Can be used to retrieve associated entities and metadata the relation. | ||
- `Schema` - Global handling of the schema. | ||
Can be used to query entities and relations. | ||
- `EntitySchema` - Handling of a single entity type. | ||
Can be used to query relations and metadata about the entity. | ||
- `RelationDefinitionSchema` - Handling of a single relation. | ||
Can be used to retrieve associated entities and metadata the relation. | ||
The `Schema` class is created from the JSON schema returned by the API. | ||
The `Client.schema()` method takes care of this for you. | ||
If your schema does not change often, it is recommended to export it using the following command | ||
(replace `<YOUR_INSTANCE_NAME>` by the name of your instance): | ||
(replace `<YOUR_INSTANCE_NAME>` by the name of your instance): | ||
```bash | ||
cubicweb-ctl export-schema -f json <YOUR_INSTANCE_NAME> | ||
``` | ||
``` | ||
@@ -159,2 +191,3 @@ You can then manually create the Schema object by passing your JSON schema to its constructor. | ||
``` | ||
`EntitySchema` and `RelationDefinitionSchema` objects should not be created manually. | ||
@@ -186,3 +219,3 @@ These are returned when querying a `Schema` object. | ||
cubicweb-ctl export-schema -f typescript <YOUR_INSTANCE_NAME> | ||
``` | ||
``` | ||
@@ -195,3 +228,3 @@ This command will generate a file `schema.ts` containing the typings. | ||
This is intended to prevent errors if the JSON schema changes and not the TS schema.** | ||
You must export both the JSON schema and TypeScript schema to use the typings. | ||
You must export both the JSON schema and TypeScript schema to use the typings. | ||
@@ -211,3 +244,3 @@ ```js | ||
All `@cubicweb` libraries are in the [cubicwebjs monorepo](https://forge.extranet.logilab.fr/cubicweb/cubicwebjs). | ||
Please refer to the main README. | ||
Please refer to the main README. | ||
@@ -214,0 +247,0 @@ ## Get Help |
@@ -0,1 +1,2 @@ | ||
import type { Authenticator } from "../Authenticator.js"; | ||
import { ValidationError } from "../errors.js"; | ||
@@ -12,2 +13,6 @@ import { RawSchema } from "../schema/raw/Schema.js"; | ||
interface ApiOptions { | ||
authenticator?: Authenticator; | ||
} | ||
/** | ||
@@ -85,2 +90,3 @@ * Type representing valid final values to use as parameters in a RQL query. | ||
private _binaryApiUrl: string; | ||
private _authenticator?: Authenticator; | ||
@@ -97,3 +103,3 @@ /** | ||
*/ | ||
constructor(apiUrl: string) { | ||
constructor(apiUrl: string, options: ApiOptions) { | ||
this._apiUrl = apiUrl; | ||
@@ -106,2 +112,3 @@ this._rqlApiUrl = this.getApiRoute("rql"); | ||
this._binaryApiUrl = this.getApiRoute("binary"); | ||
this._authenticator = options.authenticator; | ||
} | ||
@@ -123,5 +130,4 @@ | ||
async schema(): Promise<RawSchema> { | ||
return nonNullFetchApi<RawSchema>(this._schemaApiUrl, { | ||
return this.nonNullFetchApi<RawSchema>(this._schemaApiUrl, { | ||
method: "GET", | ||
credentials: "include", | ||
}); | ||
@@ -139,3 +145,3 @@ } | ||
try { | ||
await fetchApi<null>(this._loginApiUrl, { | ||
await this.fetchApi<null>(this._loginApiUrl, { | ||
method: "POST", | ||
@@ -146,3 +152,2 @@ body: JSON.stringify({ | ||
}), | ||
credentials: "include", | ||
}); | ||
@@ -161,5 +166,4 @@ return true; | ||
async logout(): Promise<void> { | ||
await fetchApi<null>(this._logoutApiUrl, { | ||
await this.fetchApi<null>(this._logoutApiUrl, { | ||
method: "POST", | ||
credentials: "include", | ||
}); | ||
@@ -174,5 +178,4 @@ } | ||
async currentUser(): Promise<CurrentUser> { | ||
return await nonNullFetchApi<CurrentUser>(this._currentUserApiUrl, { | ||
return await this.nonNullFetchApi<CurrentUser>(this._currentUserApiUrl, { | ||
method: "GET", | ||
credentials: "include", | ||
}); | ||
@@ -193,5 +196,4 @@ } | ||
}); | ||
return await nonNullFetchApi<Blob>(this._binaryApiUrl + params, { | ||
return await this.nonNullFetchApi<Blob>(this._binaryApiUrl + params, { | ||
method: "GET", | ||
credentials: "include", | ||
}); | ||
@@ -240,7 +242,6 @@ } | ||
const resultSets = await nonNullFetchApi<RawTransactionResult>( | ||
const resultSets = await this.nonNullFetchApi<RawTransactionResult>( | ||
this._rqlApiUrl, | ||
{ | ||
method: "POST", | ||
credentials: "include", | ||
body: formData, | ||
@@ -253,7 +254,6 @@ } | ||
private async jsonTransaction(transaction: Transaction) { | ||
const resultSets = await nonNullFetchApi<RawTransactionResult>( | ||
const resultSets = await this.nonNullFetchApi<RawTransactionResult>( | ||
this._rqlApiUrl, | ||
{ | ||
method: "POST", | ||
credentials: "include", | ||
body: JSON.stringify(this.getTransactionParams(transaction)), | ||
@@ -281,84 +281,94 @@ } | ||
} | ||
} | ||
/** | ||
* Behaves the same as `fetchAPI` but forbids null responses. | ||
* If this function detects a null response from the API, | ||
* the promise will be rejected with a 500 error code. | ||
* | ||
* @param input The API route to use | ||
* @param init Additional request parameters | ||
* @returns A promise with the non-null fetched result | ||
*/ | ||
async function nonNullFetchApi<R = unknown>( | ||
input: RequestInfo, | ||
init?: RequestInit | ||
) { | ||
const result = await fetchApi<R>(input, init); | ||
if (result == null) { | ||
const error: ApiErrorResponse = { | ||
status: 500, | ||
title: "Unexpected null response", | ||
message: "Response was null but a value was expected", | ||
}; | ||
throw error; | ||
/** | ||
* Behaves the same as `fetchAPI` but forbids null responses. | ||
* If this function detects a null response from the API, | ||
* the promise will be rejected with a 500 error code. | ||
* | ||
* @param input The API route to use | ||
* @param init Additional request parameters | ||
* @returns A promise with the non-null fetched result | ||
*/ | ||
private async nonNullFetchApi<R = unknown>(url: string, init: RequestInit) { | ||
const result = await this.fetchApi<R>(url, init); | ||
if (result == null) { | ||
const error: ApiErrorResponse = { | ||
status: 500, | ||
title: "Unexpected null response", | ||
message: "Response was null but a value was expected", | ||
}; | ||
throw error; | ||
} | ||
return result; | ||
} | ||
return result; | ||
} | ||
/** | ||
* Sends a request to the given API route with the `Content-Type` header set and waits for a response. | ||
* The returned promise will be rejected if the API returns HTTP error codes. | ||
* The rejected promise will contain an `ApiErrorResponse` object. | ||
* | ||
* @param input The API route to use | ||
* @param init Additional request parameters | ||
* @returns A promise with the fetched result | ||
*/ | ||
async function fetchApi<R = unknown>( | ||
input: RequestInfo, | ||
init?: RequestInit | ||
): Promise<R | null> { | ||
let headers = init?.headers; | ||
if (init?.method && init.method !== "GET") { | ||
headers = { | ||
// CSRF custom header necessary for POST requests | ||
"X-Client-Name": "XMLHttpRequest", | ||
}; | ||
// Browsers will automatically set the multipart content type | ||
// with the right boundary if the body is FormData | ||
if (!(init.body instanceof FormData)) { | ||
headers["Content-Type"] = "application/json;charset=UTF-8"; | ||
/** | ||
* Sends a request to the given API route with the `Content-Type` header set and waits for a response. | ||
* The returned promise will be rejected if the API returns HTTP error codes. | ||
* The rejected promise will contain an `ApiErrorResponse` object. | ||
* | ||
* @param input The API route to use | ||
* @param init Additional request parameters | ||
* @returns A promise with the fetched result | ||
*/ | ||
private async fetchApi<R = unknown>( | ||
url: string, | ||
init: RequestInit | ||
): Promise<R | null> { | ||
const headers = new Headers(init.headers); | ||
// Add custom header used as CSRF protection | ||
// note: it is only necessary for non GET requests but can also be useful | ||
// while debugging. | ||
if (!headers.has("X-Client-Name")) { | ||
headers.append("X-Client-Name", "XMLHttpRequest"); | ||
} | ||
headers = { | ||
...headers, | ||
...init?.headers, | ||
}; | ||
} | ||
const response = await fetch(input, { | ||
...init, | ||
headers, | ||
}); | ||
const status = response.status; | ||
if (status >= 200 && status < 300) { | ||
if (status === 204) { | ||
return null; | ||
// Add a "Content-Type" header whenever a body is passed. | ||
// The header might already have been set (either by the caller of this | ||
// function or by and encoder) | ||
if ( | ||
init.body && | ||
!headers.has("Content-Type") && | ||
!(init.body instanceof FormData) | ||
) { | ||
headers.append("Content-Type", "application/json;charset=UTF-8"); | ||
} | ||
try { | ||
return await response.json(); | ||
} catch (e) { | ||
console.error(e); | ||
return null; | ||
init.headers = headers; | ||
// Authenticate request | ||
if (this._authenticator) { | ||
const authenticatedRequest = await this._authenticator.authenticate( | ||
url, | ||
init | ||
); | ||
url = authenticatedRequest.url; | ||
init = authenticatedRequest.init; | ||
} | ||
} else { | ||
let json; | ||
try { | ||
json = await response.json(); | ||
} catch (e) { | ||
console.error(e); | ||
throw { status, title: "Error", message: "" }; | ||
// Execute request | ||
const response = await fetch(url, init); | ||
// Parse response body and handle errors | ||
const status = response.status; | ||
if (status >= 200 && status < 300) { | ||
if (status === 204) { | ||
return null; | ||
} | ||
try { | ||
return await response.json(); | ||
} catch (e) { | ||
console.error(e); | ||
return null; | ||
} | ||
} else { | ||
let json; | ||
try { | ||
json = await response.json(); | ||
} catch (e) { | ||
console.error(e); | ||
throw { status, title: "Error", message: "" }; | ||
} | ||
throw { status, ...json }; | ||
} | ||
throw { status, ...json }; | ||
} | ||
} |
@@ -0,1 +1,2 @@ | ||
import { Authenticator } from "../Authenticator.js"; | ||
import { Schema } from "../schema/classes/Schema.js"; | ||
@@ -8,2 +9,6 @@ import Api, { RQLQueryParams, CurrentUser } from "./Api.js"; | ||
export interface ClientOptions { | ||
authenticator?: Authenticator; | ||
} | ||
/** | ||
@@ -16,3 +21,2 @@ * Class used to communicate with a CubicWeb instance's API. | ||
private api: Api; | ||
/** | ||
@@ -25,4 +29,4 @@ * Class used to communicate with a CubicWeb instance's API. | ||
*/ | ||
constructor(apiUrl: string) { | ||
this.api = new Api(apiUrl); | ||
constructor(apiUrl: string, options?: ClientOptions) { | ||
this.api = new Api(apiUrl, options ?? {}); | ||
} | ||
@@ -29,0 +33,0 @@ |
@@ -24,3 +24,3 @@ // Raw Schema | ||
export { ResultSet, ResultSetRow, ResultSetCell } from "./api/ResultSet.js"; | ||
export { default as Client } from "./api/Client.js"; | ||
export { default as Client, ClientOptions } from "./api/Client.js"; | ||
export { Transaction } from "./api/transaction/Transaction.js"; | ||
@@ -31,1 +31,4 @@ export { TransactionResult } from "./api/transaction/TransactionResult.js"; | ||
export { RQLQueryRowRef, RQLQueryCellRef } from "./api/query/references.js"; | ||
// Authenticators | ||
export { Authenticator } from "./Authenticator.js"; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
218574
122
4636
1
242