Skip to content
Snippets Groups Projects
Unverified Commit 7ec9ed44 authored by Steve Reis's avatar Steve Reis Committed by gitbook-bot
Browse files

GitBook: [#26] No subject

parent b4e22392
No related branches found
No related tags found
No related merge requests found
...@@ -21,5 +21,10 @@ ...@@ -21,5 +21,10 @@
* [Create a connector](for-developers/gateway/connector/create-a-connector.md) * [Create a connector](for-developers/gateway/connector/create-a-connector.md)
* [Parsing response with JSONdata](for-developers/connector/Parsing-response-with-JSONata.md) * [Parsing response with JSONdata](for-developers/connector/Parsing-response-with-JSONata.md)
* [Frontend](for-developers/frontend/README.md) * [Frontend](for-developers/frontend/README.md)
* [Update GraphQL Queries](for-developers/frontend/Update-queries-GrahpQL-in-the-frontend.md) * [GraphQL](for-developers/frontend/graphql/README.md)
* [📊 Visualisations](for-developers/frontend/visualisations.md) * [Unions and interfaces](for-developers/frontend/graphql/unions-and-interfaces.md)
* [Update GraphQL Queries](for-developers/frontend/graphql/update-queries-grahpql-in-the-frontend.md)
* [📖 Storybook](for-developers/frontend/visualisations.md)
* [👩🍳 Recipes](for-developers/recipes/README.md)
* [🚧 Add a visualization](for-developers/recipes/add-a-visualization.md)
* [Add an algorithm handler on Exareme](for-developers/recipes/add-an-algorithm-handler-on-exareme.md)
# GraphQL
---
description: Abstract schema types
---
# Unions and interfaces
**Unions** and **interfaces** are abstract GraphQL types that enable a schema field to return one of multiple object types.
Read more about [unions and interface](https://www.apollographql.com/docs/apollo-server/schema/unions-interfaces/).
In order to be correctly interpreted in the Frontend, especially when dealing [with fragments](https://github.com/apollographql/apollo-client/issues/7050), we have to provide to the cache the possible types for a fragment. 
{% hint style="warning" %}
In the file `cache.tsx`, within the parameter `possiblesTypes` you should provide a list of types that you expect to see in the GraphQL responses, if a type is missing this will result in a empty response for the specific type missing. 
{% endhint %}
# 📊 Visualisations # 📖 Storybook
To see the different possible visualisations in the frontend we have integrated [storybook.js](https://storybook.js.org/) directly in the frontend. To see the different possible visualisations in the frontend we have integrated [storybook.js](https://storybook.js.org/) directly in the frontend.
......
...@@ -117,6 +117,7 @@ The connector has it's own part of configuration, it's mainly parameters that ar ...@@ -117,6 +117,7 @@ The connector has it's own part of configuration, it's mainly parameters that ar
| name | default | description | | name | default | description |
| ----------- | ------- | ------------------------------------------------------------------------------------------------------- | | ----------- | ------- | ------------------------------------------------------------------------------------------------------- |
| hasGrouping | false | Define if the connector is able to make query grouping by nominal variable (mainly used for histograms) | | hasGrouping | false | Define if the connector is able to make query grouping by nominal variable (mainly used for histograms) |
| hasFilters | true | Define if the engine behind the connector is able to manage filters |
| hasGalaxy | false | `Deprecated`. Only used by Exareme engine | | hasGalaxy | false | `Deprecated`. Only used by Exareme engine |
These elements can be configured by the function `getConfiguration`. These elements can be configured by the function `getConfiguration`.
......
# Decorators # Decorators
The request and the response made by `GraphQL` are a bit different then what you should expect from a normal REST API. For this purpose and as this is something that is often used, two decorators have been implemented to inject the request with the `@GQLRequest`, the response with `@GQLResponse` or the user with the `@CurrentUser`.  The request and response made by `GraphQL` are a bit different then what you should expect from a normal REST API. For this purpose and as this is something that is often used, two decorators have been implemented to inject the request. The request can be injected with the decorator `@GQLRequest` and the response with `@GQLResponse` and finally the user can also be injected by using the `@CurrentUser`. 
These 3 decorators can only be use in a GraphQL context, it will fail if it's a standard API REST request. These 3 decorators can only be use in a GraphQL context, it will fail if it's a standard API REST request.
# 👩🍳 Recipes
# 🚧 Add a visualization
ResultUnion, gateway and frontend
---
description: >-
This page describe how algorithm's outputs are processed with Exareme (I & II)
connector
---
# Add an algorithm handler on Exareme
Exareme algorithms' ouputs are processed based on the design pattern [chain of responsibility](https://refactoring.guru/design-patterns/chain-of-responsibility). Basically every algorithm has an handler that can decide to process the output. Each handler has the responsibility to know if it can handle the current output or not. 
### Add a new handler 
Each handler should implements the `ResultHandler` interface. The handler can also directly extends the class `BaseHandler` which provides default implementation of the previous interface.
For this demonstration we will create a new Handler called `MyAlgorithm`. First we will create a new file inside the `src/engine/connectors/exareme/handlers/algorithms` folder.
{% code title="my-algorithm.handler.ts" lineNumbers="true" %}
```typescript
export default class MyAlgorithmHandler extends BaseHandler {
handle(experiment: Experiment, data: any, domain?: Domain): void {
...
}
}
```
{% endcode %}
The handler can either process the request or pass it to the next handler along the chain. For this concern we will define a new method in our algorithm to define the ability or not to handle the request.
{% code lineNumbers="true" %}
```typescript
export default class MyAlgorithmHandler extends BaseHandler {
public static readonly ALGO_NAME = 'myAlgorithmName';
private canHandle(data: any) {
return (
data &&
data.mySuperProperty &&
data.algorithmName = MyAlgorithmHandler.ALGO_NAME
);
}
handle(experiment: Experiment, data: any, domain? Domain) {
if (!this.canHandle(data: any)) return super.handle(experiment, data, domain);
//Process the data
}
}
```
{% endcode %}
{% hint style="warning" %}
Make sure to call the next handler either by calling directly `this.next(...)` or `super.handler(...)` otherwise it will end the chaining system
{% endhint %}
The idea of the chaining system is to improve the `Experiment` object that is passed along the chain. This object is acting like a Request object, it's mutable, then you can modify it to fit the need of your handler.
Here we will add a result inside our experiment for the purpose of the demonstration. 
{% code lineNumbers="true" %}
```typescript
export default class MyAlgorithmHandler extends BaseHandler {
public static readonly ALGO_NAME = 'myAlgorithmName';
private canHandle(data: any) {
return (
data &&
data.mySuperProperty &&
data.algorithmName = MyAlgorithmHandler.ALGO_NAME
);
}
private getTableResult(data: any): TableResult {
const tableResult: TableResult = {
name: 'Results',
tableStyle: TableStyle.NORMAL,
headers: ['name', 'value'].map((name) => ({ name, type: 'string' })),
data: [
'n_obs',
't_value',
'ci_upper',
'cohens_d',
].map((name) => [
name,
data[name],
]),
};
return tableResult;
}
handle(experiment: Experiment, data: any, domain? Domain) {
if (!this.canHandle(data: any)) return super.handle(experiment, data, domain);
const tableResult = this.getTableResult(data);
if (tableResult) exp.results.push(tableResult);
}
}
```
{% endcode %}
In lines 34 and 35 we know that our handler is up to deal with the request, so our handle can produce the result wanted and add it the experiment. 
Now we can decide to either end the request here or pass it the next handler. As we know that only one algorithm should process the output we can end the request here by not calling the next handle.
#### Add it to the chaining system
Now that we have created our algorithm we should add it to the chaining system, open the file `src/engine/connectors/exareme/handlers/index.ts` and simply add our new class to the list
{% code title="index.ts" lineNumbers="true" %}
```typescript
const start = new PearsonHandler();
start
.setNext(new DescriptiveHandler())
.setNext(new AnovaOneWayHandler())
.setNext(new PCAHandler())
.setNext(new LinearRegressionHandler())
.setNext(new MyAlgorithmHandler())
.setNext(new RawHandler()); // should be last handler as it works as a fallback (if other handlers could not process the results)
export default (exp: Experiment, data: unknown, domain: Domain): Experiment => {
start.handle(exp, data, domain);
return exp;
};
```
{% endcode %}
The handlers' order is important, if you want to check something in priority, just put it in the top of the list. 
{% hint style="info" %}
This order can be useful if you want to process error at first. You can easily create a connector that could handle global error before passing along the chain system
{% endhint %}
{% hint style="warning" %}
Don't forget to write a unit test along of your handler, conventionally called `my-algorithm.handler.spec.ts`.
{% endhint %}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment