grin-api-sdk
Grin's typescript sdk, containing apis for our services and common enums, methods and utilities.
Installing
First you need to login to npmjs registery using our rnd account.
Get the password from the password manager / somebody in the team, then run
$ npm login
and follow the steps.
After logging in, you can install the package.
Using npm:
$ npm install @grin-rnd/grin-api-sdk
Using yarn:
yarn add @grin-rnd/grin-api-sdk
Usage examples
AppSync Communication
Here is a short example of how to set up an access to AppSync using the Graph
module.
This example will work mostly on lambda functions, where the credentials exist on the environment variables.
Initialization
const { Graph } = require('@grin-rnd/grin-api-sdk')
const graphOperations = require('./graphql')
Graph.init('https://<UrlToYourAppsync>', {
graphOperations,
verbose: true
})
Running queries and mutations
const patient1 = await Graph.api.fetchItem('getPatient', { id: 'zdibi' })
const patient2 = await Graph.api.fetchItem('patientByUsername', { username: 'zdibi' }) // fetchItem will fetch the head of the items list
const allPatients = await Graph.api.fetchAll('listPatients')
const grinDocs = await Graph.api.search('searchDoctors', {
filter: {
email: {
match: '@get-grin'
}
}
})
console.log(grinDocs) // { items, nextToken, total } or whatever is on the query
const docEmailOnly = await Graph.api.query('getDoctor', { id: 'zdibi' }, data => data.getDoctor.email)
const updatedDoctor = await Graph.api.mutateItem('updateDoctor', {
id: 'zdibi',
_version: 1
})
Dynamic operations
The GraphAPI
class uses gql-query-builder library to generate dynamic queries without the need to include them in the operations json passed to the GraphAPI
instance.
Access the dynamic
property on your GraphAPI instance to use this feature.
Example:
Graph.api.dynamic.fetchItem({
operation: 'doctorByEmail',
variables: {
email: 'ido@get-grin.com'
},
fields: [
'id',
'_version',
{
user: [ 'id', 'username' ]
},
{
patients: [
{
items: ['id']
}
]
}
]
})
Check out the library's docs for more examples.
Graph Mocks
If your tests require complicated mocked Graph API responses, you can now use the Graph Mock module to simplify the process.
jest.mock('@grin-rnd/grin-api-sdk', () => ({
__esModule: true,
...jest.requireActual('@grin-rnd/grin-api-sdk'),
Graph: {
api: {
query: jest.fn().mockImplementation(
Graph.mockBuilder()
.mock('getPatient, 'testPatient2', { id: 'testPatient2', username: 'aaa' })
.mock('getPatient', { id: 'genericTestPatient' }) // Fallback for getPatient
.mock('doctorByEmail' (queryName, variables) => ({ // accepts also callbacks
items: [
doctorsByUsername[variables.username]
]
})
.getMockImplementation()
)
}
}
}))
Then, when your module runs getPatient, it would get the predefined value from above:
Graph.api.fetchItem('getPatient', { id: 'testPatient2' }) // will be resolved to: { id: 'testPatient2', username: 'aaa' }
The idea is that query
is the base method that being invoked by all other methods such as fetchItem
, fetchAll
, and dynamic.
With the mock builder you define which values should be returned by query and even by specific ids.
NOTE: using this feature might change the way you mock the Graph api in general. For example, instead of replacing the entire api
with a custom object, you set a spy
on the methods:
beforeEach(() => {
Graph.init('https://something.test', {
graphOperations: {}
})
jest.spyOn(Graph.api.dynamic, 'mutateItem').mockImplementation((mutationName, input) => {
return Promise.resolve({ id: input?.id })
})
jest
.spyOn(Graph.api, 'query')
.mockImplementation(
Graph.mockBuilder().mock('listStatuss', { items: statusesData.statusesList }).getMockImplementation()
)
})
GraphAPI
instance
Creating a This is an example of how to create a GraphAPI
instane, which is the class used for communication with AppSync under the hood in the Graph
module.
const { GraphAPI } = require('@grin-rnd/grin-api-sdk')
const graphOperations = require('./graphql')
const graph = new GraphAPI('https://<UrlToYourAppsync>', {
graphOperations,
verbose: true
})
// now you can call the same methods as shown in the previous section, such as fetchItem, query, mutateItem and so on.
LambdaAPI
This module wraps common types of lambda invocations.
It's capable of sending fake http requests to express lambad functions, or simply invoke the lambda with a payload.
NOTE: fake http requests DO NOT go through the API Gateway. It's simply invoke the lambda with an event structed as a http request.
const { LambdaAPI } = require('@grin-rnd/grin-api-sdk')
const lambda = new LambdaAPI(YOUR_FUNCTION_NAME_HERE)
// This will mock a post method: the first parameter is the endpoint path, and the second is the request body.
const postResponse = await lambda.post('/path/to/somewhere', {
hello: 'world'
})
// This will mock a get method, using the first parameter as the path. You can also add query parameters.
const getResponse = await lambda.get('/path/to/somewhere?hello=world')
// You can also create your own http request if the existing methods do not suite your needs:
const response = await lambda.mockHttpRequest(
'PATCH',
'/path/to/somewhere',
{ 'hello': 'world' }, // body
{ 'content-type': 'application/json' } // headers
)
// This will invoke the lambda. The object argument will be passed as the event.
const invokeResponse = await lambda.invoke({ hello: 'world' })
GrinAxios
This is just a wrapper for axios
package that implements retries mechanism using exponential backoff.
Just import GrinAxios
and use it as a regular axios package:
const { GrinAxios } = require('@grin-rnd/grin-api-sdk')
const res = await GrinAxios({
method, // GET, POST, PUT, DELETE, ...
url,
data: req.body,
headers: req.headers
})
LambdaUtils
recordParser
Use recordParser
to parse a lambda trigger DyanmoDB record to json.
const { recordParser } require('@grin-rnd/grin-api-sdk)
const record = event.Records[0]
const newImage = recordParser(record.dynamodb.NewImage)
// use newImage as a standard json
Test with SDK Test project
- remove the
@get-grin
from thepackage.json
of the sdk project (just for your testing) npm run make_link
- go to the grin api sdk test project -->
npm i
- for every change in the sdk -->
npm run make_link
--> remove node_modules in test project -->npm i