Getting started
The EVA SDK provides access to the functionality exposed by the EVA API using developer focused methods and classes. The JavaScript SDK consists of a number of packages published on NPM. Below you will find a listing of the currently available packages and their purpose.
The SDK itself and all Code samples will be written in TypeScript. The SDK provides full typings when installed through NPM but can be consumed in any JavaScript project.
Functionality
The SDK covers the following topics:
- Shared utilities
- Service calling
- Service definitions
- Redux based state management (optional)
- React/Recoil based state management (optional)
- Realtime communication using SignalR (optional)
Shared utilities
These provide shared basic functionality for all other packages.
Service calling
These are the tools needed to call a service on the EVA backend. All standard configuration, headers and response parsing/interception will be performed by these packages.
NOTE: You have to provide your application name and version to be allowed to make service calls to EVA. See example code below for the
setCoreSetting
calls.
Service definitions
These packages contain the configuration needed to call an EVA service.
All of them depend on the eva-services-core
package which should be installed at all times.
These can be used with the EVA service calling packages to have fully TypeScript typed requests and responses.
The set of EVA service definition packages will grow over time and be amended with documentation as needed.
Check the sidebar for documentation about specific topics which will detail which definitions should be installed.
There is also a list of service definition packages available
EVA Warning
The EVA backend can return special headers with warning about deprecations or other potential issues with the call being made. These message are informational and do not signify a failed call. They should however be acted upon because they might indicate you are using a deprecated service which may stop working in the future.
EVA Response error
The EVA backend can sometimes return a successful (HTTP status code) response but its response body contains data that signifies a functional error. Because applications will want to treat this as an error the EVA Service class will automatically change the response to an error and reject it.
Services will be automatically rejected based on the presence of:
Error
in JSON responseAuthentication
in JSON response that is not equal toEVA.Core.AuthenticationResults.Authenticated
(2)
Request cancelling
The EVA Service implementation is using the Fetch API with the ky library.
Fetch unlike XHR has the ability to cancel a request using an AbortController
.
The EvaService
class exposes an abort()
method that can be called when the request is underway.
This will immediately stop the network request and the call promise will throw with an error with error.name === 'AbortError'
.
Error handling
A service call error can occur on multiple levels. Anything from a syntax error, no network available or a response with an error in its JSON payload.
For consistent error handling you can check if the returned error is of type HTTPError
which is exposed from ky-universal
.
If the error is of that type an actual (JSON) response was received. The error.response
property will at that point be a fetch Response instance. Below is an example snippet for how to catch errors.
import ky from 'ky-universal';
...
try {
// Calling a service on an EvaEndpoint works the same way
//
const response = await service.call();
} catch (error) {
if (error instanceof ky.HTTPError) {
// An HTTP response error (non 2xx/3xx) or
// an Error/Authentication failure was detected in the payload
//
const httpError: ky.HTTPError = error;
const jsonError = await httpError.response.json();
console.error('Error response', jsonError);
} else if (error.name === 'AbortError') {
// Fetch abort controller was used
//
console.warn('Call was aborted');
} else {
// Any other error
//
console.error('An error occurred', error);
}
}
Redux based state management
Modern web applications often use a state management solution. The EVA SDK provides a builder to configure a ReduxJS based store. Please check the Redux store builder documentation for details on the EVA state store and how to configure or use it.
- @springtree/eva-sdk-redux-store-builder
Recoil based state management
React applications have various solutions available for state management. The EVA SDK provides ready made components and state atoms/selectors for Recoil. Please check the React/Recoil documentation for details on the EVA state store and how to configure or use it.
- @springtree/eva-sdk-react-recoil
Realtime communication
The realtime communication channels are optional and can be installed and used as needed. Please check the SignalR documentation for details on how to use EVA realtime communication.
- @springtree/eva-sdk-signalr
Installation
Install the following packages as a baseline for calling services and to use the redux store:
npm i \
@springtree/eva-services-core \
@springtree/eva-sdk-core-logger \
@springtree/eva-sdk-core-settings \
@springtree/eva-sdk-core-service \
@springtree/eva-sdk-core-available-services \
@springtree/eva-sdk-redux-store-builder \
url-parse \
pubsub-js \
ky \
ky-universal \
redux \
redux-logic \
rxjs \
uuid
npm i -D @types/uuid @types/pubsub-js
You can install additional service packages as needed:
# Example, there are more
npm i @springtree/eva-services-admin
If you need real-time communication you can install the SignalR package as well:
npm i @microsoft/signalr @springtree/eva-sdk-signalr
Usage
If you installed the baseline you can setup the service interceptors and create a redux store with the following code below. You will need to know your EVA backend URL. There is also a simpler service call only starting setup available.
import { ReducersMapObject } from 'redux';
import { Logic } from 'redux-logic';
import { setCoreSetting } from '@springtree/eva-sdk-core-settings';
import { bootstrapEndpoint } from '@springtree/eva-sdk-core-service';
import { evaAvailableServices } from '@springtree/eva-sdk-core-available-services';
import {
StoreBuilder,
IEvaReduxStoreDefaultShape,
createCurrentUserTokenAction,
} from '@springtree/eva-sdk-redux-store-builder';
// Optionally activate EVA service interceptors
//
evaAvailableServices.activate();
// Set our application details to identify the client application for EVA analytics.
// This is mandatory and the SDK will throw an error if you do not provide these.
//
setCoreSetting('appName', 'MyApp');
setCoreSetting('appVersion', '1.0.0');
// TODO: Change this url to your EVA backend url
//
const url = 'https://api.eva-dev.on-eva.io';
// Declare your redux store extensions
// Please see the redux builder package for more details
//
export interface IMyReduxStore extends IEvaReduxStoreDefaultShape {
// TODO: Add your state properties
}
const reducers: ReducersMapObject<Partial<IMyReduxStore>> = {
// TODO: Add your state reducers
};
const logics: Logic[] = [
// TODO: Add your state effects logic
];
// Create the default EVA redux store which contains current user support
// out-of-the-box
//
const builder = new StoreBuilder<IMyReduxStore>();
const store = builder.createStore({
reducers,
logics,
initialState: { endpointUrl: url },
});
// (Optional) if you do not want the first call to trigger bootstrap do it yourself
//
const endpoint = await bootstrapEndpoint({ uri: url });
// Restore previous user token (ex. from local storage)
//
const setTokenAction = createCurrentUserTokenAction({ token: 'myToken' });
store.dispatch(setTokenAction);
// If you want to call a service outside the redux store use the endpoint
// See the EvaEndpoint documentation for more details
//
try {
await endpoint.callService( ... );
} catch ( error ) {
...
}
There is a StackBlitz playground available to try out the SDK.