@seanferguson/the-one-sdk
v0.2.0
Published
An sdk for accessing LOTR data through https://the-one-api.dev/
Downloads
3
Readme
The One SDK
SDK for accessing LOTR api hosted at https://the-one-api.dev/
Prerequisites
This project requires NodeJS (version 14 or later) and NPM. Node and NPM are really easy to install. To make sure you have them available on your machine, try running the following command.
$ npm -v && node -v
7.24.0
v16.10.0
Table of contents
Installation
To install:
$ npm install --save @seanferguson/the-one-sdk
Or if you prefer using Yarn:
$ yarn add @seanferguson/the-one-sdk
Usage
const { Client } = require('@seanferguson/the-one-sdk')
// initialize client with your personal api token
const client = new Client({ token: process.env.API_TOKEN })
// make requests to the api
const quotes = await client.getMovieQuotes('5cd95395de30eff6ebccde5b')
Retry
If any of your requests recieve a rate limit we will retry 10 times before returning a failure. We insert an exponential backoff in wait times between retries starting with 2 seconds.
Pagination
Pagination for relevant endpoints is done by passing an options object to the call with any of the pagination fields documented here. This is entirely optional and if omitted will default to sane values
At the time of this writing the options are:
- limit - the maximum number of results to return
- offset - the number of entries to skip
- page - a shorthand for setting offset to limit * page
Sorting
Sorting for relevant endpoints is done by passing an options object to the call with the sort option specified here. This is entirely optional.
Filters
Filtering for relevant endpoints is done by passing an options object to the call with the filters option specified. The filters object is of the following format:
{
fieldYouWouldLikeToFilterOn: {
op: OPS.MATCH, // or other operators as desired
value: 'the value I was looking for',
}
}
See a below list of potential operators and the corresponding valid values
Operators
MATCH
{
fieldYouWouldLikeToFilterOn: {
op: OPS.MATCH,
value: 'the value I was looking for',
}
}
We also allow this shorthand for specifying a MATCH filter which is treated identically to the above:
{
fieldYouWouldLikeToFilterOn: 'the value I was looking for'
}
The MATCH operator accepts a primitive type, an array, or a RegExp as it's value. If the value is a primitive type it checks for records matching the value exactly. If the value is an array it checks for an exact match with any of the values in the array. If the value is a RegExp object it will check for objects whose values match that regular expression.
Using RegExp in a match has undefined behavior if the field being filtered on is not a string field.
NOT_MATCH
{
fieldYouWouldLikeToFilterOn: {
op: OPS.NOT_MATCH,
value: 'the value I was looking for',
}
}
The NOT_MATCH operator is a reversed version of the match operator. See Above for details. Note that no shorthand for this operator exists.
EXISTS
{
fieldYouWouldLikeToFilterOn: {
op: OPS.EXISTS,
}
}
We also allow this shorthand for specifying an EXISTS filter which is treated identically to the above:
{
fieldYouWouldLikeToFilterOn: true
}
the EXISTS operator checks for the existence of the field in question. It does not require a value and if one is provided it will be ignored.
NOT_EXISTS
{
fieldYouWouldLikeToFilterOn: {
op: OPS.NOT_EXISTS,
}
}
We also allow this shorthand for specifying a NOT_EXISTS filter which is treated identically to the above:
{
fieldYouWouldLikeToFilterOn: false
}
The NOT_EXISTS operator checks for the non-existence of the field in question. It does not require a value and if one is provided it will be ignored.
GT
{
fieldYouWouldLikeToFilterOn: {
op: OPS.GT,
value: 7,
}
}
The GT operator checks for records with a field greater than the value provided. the value provided must be of the same type as the field.
GTE
{
fieldYouWouldLikeToFilterOn: {
op: OPS.GTE,
value: 7,
}
}
The GTE operator checks for records with a field greater than or equal to the value provided. the value provided must be of the same type as the field.
LT
{
fieldYouWouldLikeToFilterOn: {
op: OPS.LT,
value: 7,
}
}
The LT operator checks for records with a field less than the value provided. the value provided must be of the same type as the field.
LTE
{
fieldYouWouldLikeToFilterOn: {
op: OPS.LTE,
value: 7,
}
}
The LTE operator checks for records with a field less than or equal to the value provided. the value provided must be of the same type as the field.
Available calls
getMovieQuotes
const { Client } = require('@seanferguson/the-one-sdk')
const client = new Client({ token: process.env.API_TOKEN })
const quotes = await client.getMovieQuotes('5cd95395de30eff6ebccde5b', {
sort: 'dialog:asc',
limit: 1000,
page: 1,
offset: 3,
})
getMovie
const { Client } = require('@seanferguson/the-one-sdk')
const client = new Client({ token: process.env.API_TOKEN })
const movie = await client.getMovie('5cd95395de30eff6ebccde5b')
getMovies
const { Client, OPS } = require('@seanferguson/the-one-sdk')
const client = new Client({ token: process.env.API_TOKEN })
const quotes = await client.getMovieQuotes('5cd95395de30eff6ebccde5b', {
sort: 'dialog:asc',
limit: 1000,
page: 1,
offset: 3,
filters: {
academyAwardWins: {
op: OPS.GTE,
value: 11
},
otherFieldToFilterOn: {
op: OPS.MATCH,
value: 'exactValueYouAreLookingFor'
}
}
})
For more usage examples check out the tests :)
Potential Future Improvements
- Add simple way to insert test stub to enable easily mocking the package in tests
Could be fairly easily handled in client by abstracting the creation of the client instance.
//in customer code
let client = new Client({ token: process.env.API_TOKEN })
const stubClient = (stub) => {
client = stub
}
const getClient = () => client
Downside of this approach is callint getClient everywhere is less ergonomic than just importing a client.
- Allow configuration of retry behavior
Would we want this on a per call basis or a per client basis? Per call allows for maximum of flexibility. If a call is in my job system I might be willing to retry for a lot longer than if it's embedded in an http request handler. You could just create multiple client's for this since a client costs basically no overhead. Per client has the benefit of being able to set sane defaults and then never worry about them again. I suppose Ideally we'd want both, but more practically I'd prioritize per client handling since creating lots of clients doesn't hurt.
Contributing
- Fork it!
- Create your feature branch:
git checkout -b my-new-feature
- Add your changes:
git add .
- Commit your changes:
git commit -am 'Add some feature'
- Push to the branch:
git push origin my-new-feature
- Submit a pull request :sunglasses:
Versioning
We use SemVer for versioning. For the versions available, see the tags on this repository.
Authors
- Sean Ferguson - Initial work - Sean Ferguson
License
MIT License © Sean Ferguson