@spinque/query-api
Advanced tools
Comparing version 0.13.0 to 0.14.0
@@ -7,52 +7,37 @@ import { ResultsResponse, StatisticsResponse } from '.'; | ||
export declare class Api { | ||
private _baseUrl; | ||
private _version?; | ||
private _workspace?; | ||
private _api?; | ||
private _config?; | ||
private _authentication?; | ||
private _authenticator?; | ||
constructor(apiConfig?: ApiConfig); | ||
/** | ||
* Getter for baseUrl | ||
* URL to the Spinque Query API deployment. | ||
* | ||
* @default https://rest.spinque.com/ | ||
*/ | ||
get baseUrl(): string; | ||
baseUrl: string; | ||
/** | ||
* Setter for baseUrl | ||
* Version of the Spinque Query API deployment. | ||
* | ||
* @default 4 | ||
*/ | ||
set baseUrl(value: string); | ||
version?: string | undefined; | ||
/** | ||
* Getter for version | ||
* Name of the Spinque workspace that should be addressed. | ||
* The Spinque Desk administrator working on your project knowns this value. | ||
*/ | ||
get version(): string | undefined; | ||
get accessToken(): string | undefined; | ||
workspace?: string; | ||
/** | ||
* Setter for version | ||
* Name of the API that is provided by the workspace. | ||
* The Spinque Desk administrator working on your project knowns this value. | ||
*/ | ||
set version(value: string | undefined); | ||
api?: string; | ||
/** | ||
* Getter for workspace | ||
* Name of the configuration of the Spinque workspace that should be used. | ||
* Usually, this is something like 'production', 'development' or 'default'. | ||
* The Spinque Desk administrator working on your project knowns this value. | ||
* | ||
* @default default | ||
*/ | ||
get workspace(): string | undefined; | ||
config?: string | undefined; | ||
private _authentication?; | ||
private _authenticator?; | ||
constructor(apiConfig?: ApiConfig); | ||
get accessToken(): string | undefined; | ||
/** | ||
* Setter for workspace | ||
*/ | ||
set workspace(value: string | undefined); | ||
/** | ||
* Getter for API name | ||
*/ | ||
get api(): string | undefined; | ||
/** | ||
* Setter for API name | ||
*/ | ||
set api(value: string | undefined); | ||
/** | ||
* Getter for configuration name | ||
*/ | ||
get config(): string | undefined; | ||
/** | ||
* Setter for configuration name | ||
*/ | ||
set config(value: string | undefined); | ||
/** | ||
* Getter for authentication configuration | ||
@@ -59,0 +44,0 @@ */ |
113
dist/Api.js
@@ -51,19 +51,36 @@ "use strict"; | ||
function Api(apiConfig) { | ||
this._baseUrl = DEFAULT_BASE_URL; | ||
this._version = '4'; | ||
this._config = 'default'; | ||
/** | ||
* URL to the Spinque Query API deployment. | ||
* | ||
* @default https://rest.spinque.com/ | ||
*/ | ||
this.baseUrl = DEFAULT_BASE_URL; | ||
/** | ||
* Version of the Spinque Query API deployment. | ||
* | ||
* @default 4 | ||
*/ | ||
this.version = '4'; | ||
/** | ||
* Name of the configuration of the Spinque workspace that should be used. | ||
* Usually, this is something like 'production', 'development' or 'default'. | ||
* The Spinque Desk administrator working on your project knowns this value. | ||
* | ||
* @default default | ||
*/ | ||
this.config = 'default'; | ||
if (apiConfig && apiConfig.baseUrl) { | ||
this._baseUrl = apiConfig.baseUrl; | ||
this.baseUrl = apiConfig.baseUrl; | ||
} | ||
if (apiConfig && apiConfig.version) { | ||
this._version = apiConfig.version; | ||
this.version = apiConfig.version; | ||
} | ||
if (apiConfig && apiConfig.workspace) { | ||
this._workspace = apiConfig.workspace; | ||
this.workspace = apiConfig.workspace; | ||
} | ||
if (apiConfig && apiConfig.api) { | ||
this._api = apiConfig.api; | ||
this.api = apiConfig.api; | ||
} | ||
if (apiConfig && apiConfig.config) { | ||
this._config = apiConfig.config; | ||
this.config = apiConfig.config; | ||
} | ||
@@ -81,34 +98,2 @@ if (apiConfig && apiConfig.authentication) { | ||
} | ||
Object.defineProperty(Api.prototype, "baseUrl", { | ||
/** | ||
* Getter for baseUrl | ||
*/ | ||
get: function () { | ||
return this._baseUrl; | ||
}, | ||
/** | ||
* Setter for baseUrl | ||
*/ | ||
set: function (value) { | ||
this._baseUrl = value; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Api.prototype, "version", { | ||
/** | ||
* Getter for version | ||
*/ | ||
get: function () { | ||
return this._version; | ||
}, | ||
/** | ||
* Setter for version | ||
*/ | ||
set: function (value) { | ||
this._version = value; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Api.prototype, "accessToken", { | ||
@@ -122,50 +107,2 @@ get: function () { | ||
}); | ||
Object.defineProperty(Api.prototype, "workspace", { | ||
/** | ||
* Getter for workspace | ||
*/ | ||
get: function () { | ||
return this._workspace; | ||
}, | ||
/** | ||
* Setter for workspace | ||
*/ | ||
set: function (value) { | ||
this._workspace = value; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Api.prototype, "api", { | ||
/** | ||
* Getter for API name | ||
*/ | ||
get: function () { | ||
return this._api; | ||
}, | ||
/** | ||
* Setter for API name | ||
*/ | ||
set: function (value) { | ||
this._api = value; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Api.prototype, "config", { | ||
/** | ||
* Getter for configuration name | ||
*/ | ||
get: function () { | ||
return this._config; | ||
}, | ||
/** | ||
* Setter for configuration name | ||
*/ | ||
set: function (value) { | ||
this._config = value; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Api.prototype, "authentication", { | ||
@@ -172,0 +109,0 @@ /** |
@@ -6,2 +6,2 @@ export * from './Api'; | ||
export * from './utils'; | ||
export * from './clustered-search'; | ||
export * from './clusters'; |
@@ -22,3 +22,3 @@ "use strict"; | ||
__exportStar(require("./utils"), exports); | ||
__exportStar(require("./clustered-search"), exports); | ||
__exportStar(require("./clusters"), exports); | ||
//# sourceMappingURL=index.js.map |
/** | ||
* Configuration of an API to send queries to. | ||
* Configuration of an API to send queries to. Used to instantiate the Api class. | ||
*/ | ||
@@ -4,0 +4,0 @@ export interface ApiConfig { |
{ | ||
"name": "@spinque/query-api", | ||
"version": "0.13.0", | ||
"version": "0.14.0", | ||
"description": "", | ||
@@ -9,4 +9,4 @@ "main": "dist/index.js", | ||
"build": "tsc", | ||
"demo": "npx ts-node -r tsconfig-paths/register ./demo/authentication/server/index", | ||
"docs": "npx typedoc src/index.ts", | ||
"demo": "npx ts-node -r tsconfig-paths/register ./demo/basic/clustered-search.ts", | ||
"docs": "typedoc src/index.ts", | ||
"check-format": "prettier --check \"src/**/*.ts\"", | ||
@@ -45,3 +45,4 @@ "format": "prettier --write \"src/**/*.ts\"", | ||
"tsconfig-paths": "^4.2.0", | ||
"typescript": "^4.6.2" | ||
"typescript": "^4.6.2", | ||
"typedoc": "0.24.8" | ||
}, | ||
@@ -48,0 +49,0 @@ "dependencies": { |
380
README.md
@@ -9,5 +9,20 @@ # @spinque/query-api | ||
The Spinque Query API is an HTTP API to retrieve search results for queries. Also check out the [documentation of the Spinque Query API](https://docs.spinque.com/3.0/using-apis/basic.html). | ||
The Spinque Query API is an HTTP API to retrieve search results for queries. | ||
Also check out the | ||
[documentation of the Spinque Query API](https://docs.spinque.com/3.0/using-apis/basic.html). | ||
## Table of contents | ||
- [Installing](https://github.com/spinque/query-api-ts#installing) | ||
- [Documentation](https://github.com/spinque/query-api-ts#documentation) | ||
- [Usage](https://github.com/spinque/query-api-ts#usage) | ||
- [Defining queries](https://github.com/spinque/query-api-ts#defining-queries) | ||
- [Fetching results](https://github.com/spinque/query-api-ts#fetching-results) | ||
- [Fetching using custom HTTP-library](https://github.com/spinque/query-api-ts#fetching-using-custom-http-library) | ||
- [Authentication](https://github.com/spinque/query-api-ts#authentication) | ||
- [Utility functions](https://github.com/spinque/query-api-ts#utility-functions) | ||
- [Faceted search](https://github.com/spinque/query-api-ts#faceted-search) | ||
- [Clustered search](https://github.com/spinque/query-api-ts#clustered-search) | ||
- [Vanilla JavaScript](https://github.com/spinque/query-api-ts#vanilla-javascript) | ||
## Installing | ||
@@ -23,5 +38,7 @@ | ||
Documentation for this library can be found [here](https://spinque.github.io/query-api-ts/). | ||
Documentation for this library can be found | ||
[here](https://spinque.github.io/query-api-ts/). | ||
For documentation on the Spinque Query API itself, please see [this](https://docs.spinque.com/3.0/using-apis/basic.html). | ||
For documentation on the Spinque Query API itself, please see | ||
[this](https://docs.spinque.com/3.0/using-apis/basic.html). | ||
@@ -35,7 +52,7 @@ ## Usage | ||
```typescript | ||
import { Query } from '@spinque/query-api'; | ||
import { Query } from "@spinque/query-api"; | ||
const query: Query = { | ||
endpoint: 'movie_search', | ||
parameters: { terms: 'call me' } | ||
endpoint: "movie_search", | ||
parameters: { terms: "call me" }, | ||
}; | ||
@@ -46,12 +63,13 @@ ``` | ||
Fetching results for a single query using an instance of the Api class and its `fetch` method: | ||
Fetching results for a single query using an instance of the Api class and its | ||
`fetch` method: | ||
```typescript | ||
import { Api, Query } from '@spinque/query-api'; | ||
import { Api, Query } from "@spinque/query-api"; | ||
// Configure the API with workspace, configuration and API name | ||
const api = new Api({ | ||
workspace: 'my-workspace', | ||
config: 'default', | ||
api: 'movies' | ||
workspace: "my-workspace", | ||
config: "default", | ||
api: "movies", | ||
}); | ||
@@ -61,4 +79,4 @@ | ||
const query: Query = { | ||
endpoint: 'movie_search', | ||
parameters: { terms: 'call me' } | ||
endpoint: "movie_search", | ||
parameters: { terms: "call me" }, | ||
}; | ||
@@ -76,16 +94,17 @@ | ||
Getting the URL for a request to fetch it using your own HTTP-library of preference: | ||
Getting the URL for a request to fetch it using your own HTTP-library of | ||
preference: | ||
```typescript | ||
import { urlFromQueries } from '@spinque/query-api/utils'; | ||
import { urlFromQueries } from "@spinque/query-api/utils"; | ||
const apiConfig = { | ||
workspace: 'my-workspace', | ||
config: 'default', | ||
api: 'movies' | ||
workspace: "my-workspace", | ||
config: "default", | ||
api: "movies", | ||
}; | ||
const query: Query = { | ||
endpoint: 'movie_search', | ||
parameters: { terms: 'call me' } | ||
endpoint: "movie_search", | ||
parameters: { terms: "call me" }, | ||
}; | ||
@@ -100,3 +119,5 @@ | ||
Some Spinque APIs require authentication using OAuth 2.0. The Client Credentials flow (for server applications) and PKCE flow (for browser applications) are provided by `@spinque/query-api`: | ||
Some Spinque APIs require authentication using OAuth 2.0. The Client Credentials | ||
flow (for server applications) and PKCE flow (for browser applications) are | ||
provided by `@spinque/query-api`: | ||
@@ -106,18 +127,19 @@ #### Client Credentials flow (for server applications) | ||
```typescript | ||
import { Api } from '@spinque/query-api'; | ||
import { Api } from "@spinque/query-api"; | ||
const api = new Api({ | ||
workspace: 'my-workspace', | ||
config: 'default', | ||
api: 'movies', | ||
workspace: "my-workspace", | ||
config: "default", | ||
api: "movies", | ||
authentication: { | ||
type: 'client-credentials', | ||
clientId: 'abcdefghijklmnopqrstuvwxyz', | ||
clientSecret: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', | ||
} | ||
type: "client-credentials", | ||
clientId: "abcdefghijklmnopqrstuvwxyz", | ||
clientSecret: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", | ||
tokenCachePath: "/tmp/spinque_token_cache", | ||
}, | ||
}); | ||
const query: Query = { | ||
endpoint: 'movie_search', | ||
parameters: { terms: 'call me' } | ||
endpoint: "movie_search", | ||
parameters: { terms: "call me" }, | ||
}; | ||
@@ -128,23 +150,30 @@ | ||
Note: the Client ID and Client Secret can be generated by creating a new System-to-System account in the Settings > Team Members section of Spinque Desk. | ||
The Client ID and Client Secret can be generated by creating a new | ||
System-to-System account in the Settings > Team Members section of Spinque Desk. | ||
The (optional) `tokenCachePath` saves the access token to a file. When the | ||
application is restarted, the token in the file cache will be read and reused if | ||
still valid. This is useful during development, when your application might | ||
restarted often and in-memory cache does not work. Not only does this speed | ||
things up, it also helps stay under your access token usage limits. | ||
#### PKCE flow (for browser applications) | ||
```typescript | ||
import { Api } from '@spinque/query-api'; | ||
import { Api } from "@spinque/query-api"; | ||
const api = new Api({ | ||
workspace: 'my-workspace', | ||
config: 'default', | ||
api: 'movies', | ||
workspace: "my-workspace", | ||
config: "default", | ||
api: "movies", | ||
authentication: { | ||
type: 'pkce', | ||
clientId: 'abcdefghijklmnopqrstuvwxyz', | ||
callback: 'https://my-domain.com/callback' | ||
} | ||
type: "pkce", | ||
clientId: "abcdefghijklmnopqrstuvwxyz", | ||
callback: "https://my-domain.com/callback", | ||
}, | ||
}); | ||
const query = { | ||
endpoint: 'movie', | ||
parameters: { id: 'https://imdb.com/data/movie/tt0209144' } | ||
endpoint: "movie", | ||
parameters: { id: "https://imdb.com/data/movie/tt0209144" }, | ||
}; | ||
@@ -155,34 +184,45 @@ | ||
Note: the Client ID and Callback URL cannot yet be configured from Spinque Desk. Ask your system administrator to help you out. | ||
Note: the Client ID and Callback URL cannot yet be configured from Spinque Desk. | ||
Ask your system administrator to help you out. | ||
### Utility functions | ||
Many utility functions are available for import under `@spinque/query-api/utils`. | ||
Many utility functions are available for import under | ||
`@spinque/query-api/utils`. | ||
* `urlFromQueries`, takes an ApiConfig object and an array of Query objects and returns a Spinque Query API request URL. | ||
* `pathFromQuery`, takes a single Query and returns the path of its Spinque Query API URL. | ||
* `pathFromQueries`, takes an array of Query objects and returns the path of their Spinque Query API URL. | ||
* `join`, joints together URL parts into a valid URL. | ||
* `stringifyQueries`, takes an array of Query objects and returns a string representation that can be used to e.g. store in the address baer. | ||
* `parseQueries`, takes a string from `stringifyQueries` and tries to parse it into an array of Query objects. | ||
* `stringToTupleList`, given a string, try to parse it as a tuple list (array of arrays of numbers or strings, and array of scores). | ||
* `tupleListToString`, given a tuple list, return a string representation. | ||
* `ensureTupleList`, takes a value (string, number, array of strings or numbers, or array of arrays of strings or numbers) and normalizes it into a tuple list. | ||
- `urlFromQueries`, takes an ApiConfig object and an array of Query objects and | ||
returns a Spinque Query API request URL. | ||
- `pathFromQuery`, takes a single Query and returns the path of its Spinque | ||
Query API URL. | ||
- `pathFromQueries`, takes an array of Query objects and returns the path of | ||
their Spinque Query API URL. | ||
- `join`, joints together URL parts into a valid URL. | ||
- `stringifyQueries`, takes an array of Query objects and returns a string | ||
representation that can be used to e.g. store in the address baer. | ||
- `parseQueries`, takes a string from `stringifyQueries` and tries to parse it | ||
into an array of Query objects. | ||
- `stringToTupleList`, given a string, try to parse it as a tuple list (array of | ||
arrays of numbers or strings, and array of scores). | ||
- `tupleListToString`, given a tuple list, return a string representation. | ||
- `ensureTupleList`, takes a value (string, number, array of strings or numbers, | ||
or array of arrays of strings or numbers) and normalizes it into a tuple list. | ||
See the [documentation](https://spinque.github.io/query-api-ts/) for a complete list. | ||
See the [documentation](https://spinque.github.io/query-api-ts/) for a complete | ||
list. | ||
### Faceted search | ||
Faceted search is a common use-case for application built on Spinque. | ||
This library provides a FacetedSearch to ease the interaction between queries in a faceted search setup. | ||
_Faceted search_ is a common pattern found in applications built on Spinque. | ||
This library provides a FacetedSearch to ease the interaction between queries in | ||
a faceted search setup. | ||
The following example shows how a search endpoint 'movie_search' can be used in combination with facet endpoints 'genre' and 'director'. | ||
The following example shows how a search endpoint 'movie_search' can be used in | ||
combination with facet endpoints 'genre' and 'director'. | ||
```typescript | ||
import { Api, FacetedSearch } from '@spinque/query-api'; | ||
import { Api, FacetedSearch } from "@spinque/query-api"; | ||
const query: Query = { | ||
endpoint: 'movie_search', | ||
parameters: { query: 'call me' } | ||
endpoint: "movie_search", | ||
parameters: { query: "call me" }, | ||
}; | ||
@@ -192,21 +232,24 @@ | ||
fs.addFacet('genre', 'multiple'); | ||
fs.addFacet('director', 'single'); | ||
fs.addFacet("genre", "multiple"); | ||
fs.addFacet("director", "single"); | ||
// Get results and facet options | ||
let results = await api.fetch(fs.getResultsQuery()); | ||
let genreOptions = await api.fetch(fs.getFacetQuery('genre')); | ||
let directorOptions = await api.fetch(fs.getFacetQuery('director')); | ||
let genreOptions = await api.fetch(fs.getFacetQuery("genre")); | ||
let directorOptions = await api.fetch(fs.getFacetQuery("director")); | ||
// Set the search query parameter (e.g. after the user has typed something) | ||
fs.setParameter('query', 'dia'); | ||
fs.setParameter("query", "dia"); | ||
// Get updated results and options | ||
results = await api.fetch(fs.getResultsQuery()); | ||
genreOptions = await api.fetch(fs.getFacetQuery('genre')); | ||
directorOptions = await api.fetch(fs.getFacetQuery('director')); | ||
genreOptions = await api.fetch(fs.getFacetQuery("genre")); | ||
directorOptions = await api.fetch(fs.getFacetQuery("director")); | ||
// Select some facet options | ||
fs.setFacetSelection('genre', ['https://imdb.com/data/Drama', 'https://imdb.com/data/Biography']); | ||
fs.setFacetSelection('director', 'https://imdb.com/data/PabloLarrain'); | ||
fs.setFacetSelection("genre", [ | ||
"https://imdb.com/data/Drama", | ||
"https://imdb.com/data/Biography", | ||
]); | ||
fs.setFacetSelection("director", "https://imdb.com/data/PabloLarrain"); | ||
@@ -227,9 +270,12 @@ // Get results again, now with facets applied | ||
Note that the exact same behavior can also be achieved *without* the FacetedSearch class (though it's more involved). The following two sections produce equal results: | ||
Note that the exact same behavior can also be achieved _without_ the | ||
FacetedSearch class (though it's more involved). The following two sections | ||
produce equal results: | ||
With FacetedSearch: | ||
```typescript | ||
const query: Query = { | ||
endpoint: 'movie_search', | ||
parameters: { query: 'call me' } | ||
endpoint: "movie_search", | ||
parameters: { query: "call me" }, | ||
}; | ||
@@ -239,16 +285,19 @@ | ||
fs.addFacet('genre', 'multiple'); | ||
fs.addFacet('director', 'single'); | ||
fs.addFacet("genre", "multiple"); | ||
fs.addFacet("director", "single"); | ||
let results = await api.fetch(fs.getResultsQuery()); | ||
let genreOptions = await api.fetch(fs.getFacetQuery('genre')); | ||
let directorOptions = await api.fetch(fs.getFacetQuery('director')); | ||
let genreOptions = await api.fetch(fs.getFacetQuery("genre")); | ||
let directorOptions = await api.fetch(fs.getFacetQuery("director")); | ||
fs.setParameter('query', 'dia'); | ||
fs.setParameter("query", "dia"); | ||
results = await api.fetch(fs.getResultsQuery()); | ||
genreOptions = await api.fetch(fs.getFacetQuery('genre')); | ||
directorOptions = await api.fetch(fs.getFacetQuery('director')); | ||
genreOptions = await api.fetch(fs.getFacetQuery("genre")); | ||
directorOptions = await api.fetch(fs.getFacetQuery("director")); | ||
fs.setFacetSelection('genre', ['https://imdb.com/data/Drama', 'https://imdb.com/data/Biography']); | ||
fs.setFacetSelection("genre", [ | ||
"https://imdb.com/data/Drama", | ||
"https://imdb.com/data/Biography", | ||
]); | ||
@@ -259,18 +308,19 @@ results = await api.fetch(fs.getResultsQuery()); | ||
Without FacetedSearch: | ||
```typescript | ||
const query: Query = { | ||
endpoint: 'movie_search', | ||
parameters: { query: 'call me' } | ||
endpoint: "movie_search", | ||
parameters: { query: "call me" }, | ||
}; | ||
const genreOptionsQuery: Query = { endpoint: 'genre' }; | ||
const genreOptionsQuery: Query = { endpoint: "genre" }; | ||
const genreFilterQuery: Query = { | ||
endpoint: 'genre:FILTER', | ||
parameters: { value: undefined } | ||
endpoint: "genre:FILTER", | ||
parameters: { value: undefined }, | ||
}; | ||
const directorOptionsQuery: Query = { endpoint: 'director' }; | ||
const directorOptionsQuery: Query = { endpoint: "director" }; | ||
const directorFilterQuery: Query = { | ||
endpoint: 'director:FILTER', | ||
parameters: { value: undefined } | ||
endpoint: "director:FILTER", | ||
parameters: { value: undefined }, | ||
}; | ||
@@ -290,3 +340,3 @@ | ||
query.parameters.query = 'dia'; | ||
query.parameters.query = "dia"; | ||
@@ -305,3 +355,6 @@ let resultsQuery = [query]; | ||
genreFilterQuery.parameters.value = tupleListToString(['https://imdb.com/data/Drama', 'https://imdb.com/data/Biography']); | ||
genreFilterQuery.parameters.value = tupleListToString([ | ||
"https://imdb.com/data/Drama", | ||
"https://imdb.com/data/Biography", | ||
]); | ||
@@ -319,2 +372,139 @@ let resultsQuery = [query]; | ||
### Clustered search | ||
Another common pattern in application built on Spinque is _clustered search_. A | ||
group of results (of a certain class) is positioned in the result list. Think of | ||
the group of images that's often found in your Google results. | ||
An endpoint with clustered search, will return an item of type | ||
[`rdfs:Class`](http://www.w3.org/2000/01/rdf-schema#Class) where a cluster | ||
should be placed. This item represents the cluster but it does not contain the | ||
clustered items themselves yet. Encountering it means your application has to | ||
fetch the clustered items next. The identifier of this representative item will | ||
be the class of the cluster, for example `https://schema.org/Photograph`. This | ||
can be used to fetch the cluster contents. Note: this is an opinionated | ||
convention that you could choose to diverge from. | ||
This is what the response of an endpoint with clustered search could look like. Note: results at ranks 2 and 4 represent clusters, the rest do not. | ||
```json | ||
{ | ||
"count": 5, | ||
"offset": 0, | ||
"type": ["OBJ"], | ||
"items": [ | ||
{ | ||
"probability": 1, | ||
"rank": 1, | ||
"tuple": [ | ||
{ | ||
"id": "http://example.org/1", | ||
"class": ["https://schema.org/Thing"], | ||
"attributes": { "http://example.org/attribute": "value" } | ||
} | ||
] | ||
}, | ||
{ | ||
"probability": 0.9, | ||
"rank": 2, | ||
"tuple": [ | ||
{ | ||
"id": "https://schema.org/Photograph", | ||
"class": ["http://www.w3.org/2000/01/rdf-schema#Class"] | ||
} | ||
] | ||
}, | ||
{ | ||
"probability": 0.8, | ||
"rank": 3, | ||
"tuple": [ | ||
{ | ||
"id": "http://example.org/2", | ||
"class": ["https://schema.org/Thing"], | ||
"attributes": { "http://example.org/attribute": "value" } | ||
} | ||
] | ||
}, | ||
{ | ||
"probability": 0.7, | ||
"rank": 4, | ||
"tuple": [ | ||
{ | ||
"id": "https://schema.org/Person", | ||
"class": ["http://www.w3.org/2000/01/rdf-schema#Class"] | ||
} | ||
] | ||
}, | ||
{ | ||
"probability": 0.6, | ||
"rank": 5, | ||
"tuple": [ | ||
{ | ||
"id": "http://example.org/3", | ||
"class": ["https://schema.org/Thing"], | ||
"attributes": { "http://example.org/attribute": "value" } | ||
} | ||
] | ||
} | ||
] | ||
} | ||
``` | ||
For the clusters at rank 2 and 4, the application requests the contents from the | ||
Spinque API. | ||
This library provides some tools to help build this pattern: | ||
- The | ||
[`getClusters`](https://spinque.github.io/query-api-ts/functions/getClusters.html) | ||
function, that identifies clusters in search results. | ||
- The | ||
[`isCluster`](https://spinque.github.io/query-api-ts/functions/isCluster/html) | ||
function, that returns whether an item is a cluster. | ||
An example of a clustered search implementation using these functions: | ||
```javascript | ||
const api = new Api({ | ||
workspace: "demo", | ||
config: "default", | ||
api: "demo", | ||
}); | ||
const response = await api.fetch({ | ||
endpoint: "search", | ||
parameters: { query: "utrecht" }, | ||
}); | ||
// At this stage, the normal results can already be rendered. The clusters are known but their content not yet, so | ||
// a placeholder or loading indicator should be shown instead. | ||
// Dummy rendering loop: | ||
for (let item of response.items) { | ||
if (isCluster(item)) { | ||
// show placeholder for a cluster | ||
} else { | ||
// show the full item | ||
} | ||
} | ||
// Get the clusters in the response and load their contents | ||
const clusters = getClusters(response); | ||
// Map all clusters to a request for their contents using `api.fetch` | ||
const clusterRequests = clusters.map((cluster) => | ||
api.fetch < [SpinqueResultObject] > (cluster.query) | ||
); | ||
// Await for the responses to all requests | ||
// Note: it's possible to postpone fetching cluster results until the cluster is scrolled into view | ||
const clusterResponses = await Promise.all(clusterRequests); | ||
for (let [index, cluster] of clusterResponses.entries()) { | ||
// Replace placeholder with clustered items | ||
} | ||
// Note: more cluster items could be loaded if the user indicates interest | ||
``` | ||
### Vanilla JavaScript | ||
@@ -328,9 +518,9 @@ | ||
const api = new sqa.Api({ | ||
workspace: 'my-workspace', | ||
api: 'movies' | ||
workspace: "my-workspace", | ||
api: "movies", | ||
}); | ||
const query = { | ||
endpoint: 'search', | ||
parameters: { term: 'utrecht' } | ||
endpoint: "search", | ||
parameters: { term: "utrecht" }, | ||
}; | ||
@@ -337,0 +527,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
160945
45
2368
517
11