@allthings/sdk
v11.5.0
Published
Allthings Node/Javascript SDK
Readme
Allthings Node/Javascript SDK
Contents
- Installation & Usage
- Configuration
- Authentication
- API
- Selecting response fields (
returnFields) - OAuth Implicit Grant Example
- OAuth Authorization Code Grant Example
- Release management & versioning
Installation & Usage
yarn add -DE @allthings/sdk// ESM
import { restClient } from '@allthings/sdk'
// or CJS
const { restClient } = require('@allthings/sdk')
const client = restClient({
accessToken: '043dab7447450772example1214b552838003522',
})
client
.getCurrentUser()
.then((viewer) => console.log(`Welcome back ${viewer.username}!`))Configuration
Request logs
If you want to see in your logs which url has been called during it's runtime,
you can enable them by providing LOG_REQUEST as an environment variable where the
value can be anything which is truthy.
Configuration Options
The available configuration options are outlined here:
| Option | Default | Description |
|------------------|---------|---------------------------------------------------------------------------------------------------------------------------------|
| accessToken | | API Access Token |
| clientId | | OAuth 2.0 clientId |
| clientSecret | | OAuth 2.0 client secret |
| username | | Username to use with OAuth 2.0 Password Grant authentication flow |
| password | | Password to use with OAuth 2.0 Password Grant authentication flow |
| concurrency | | Number of concurrent requests to perform in parallel. Default behavior is burst of 30/s, 1/s thereafter |
| apiUrl | | Base API url to use. Defaults to https://api.allthings.me/, respects value of the ALLTHINGS_REST_API_URL environment variable |
Authentication
@TODO
process.env.ALLTHINGS_OAUTH_CLIENT_ID process.env.ALLTHINGS_OAUTH_CLIENT_SECRET, process.env.ALLTHINGS_OAUTH_PASSWORD, process.env.ALLTHINGS_OAUTH_USERNAME,
OAuth Implicit Grant Example
@TODO
import { restClient } from '@allthings/sdk'
const client = restClient({
accessToken: '043dab7447450772example1214b552838003522',
})
client
.getCurrentUser()
.then((viewer) => console.log(`Welcome back ${viewer.username}!`))OAuth Authorization Code Grant Example
- Initialize instance of
client:
import { restClient } from '@allthings/sdk'
const client = restClient({
clientId: '5d038ef2441f4de574005c54_example',
clientSecret: '40f63f981ff082dbc8d273983ac3852c2e51e90856123156',
redirectUri: 'https://example-app.com/callback',
})- Construct a URI to send authorization request to using a
statewhich should be unique per request and hard to guess. It can be generated withclient.oauth.generateState()method:
const state = client.oauth.generateState()
const authorizationUri = client.oauth.authorizationCode.getUri(state)Direct user's browser to the constructed URI.
When user completes authentication process, he is redirected to the
redirectUrihavingcodeandstatequery string arguments, e.g.:
https://example-app.com/callback?code=ebc110bee11b2829&state=k1bt3c1d0vnfu7qkAt this point state must be validated - if it doesn't match the one generated on step 2, such request is probably malicious and should be aborted.
- Use the code extracted from query parameters on the previous step to obtain an access token:
await client.oauth.authorizationCode.requestToken(code)- Client is ready to make API requests:
const user = await client.getCurrentUser()API
Allthings SDK module
restClient()client.agentCreate()client.agentCreatePermissions()client.appCreate()client.lookupIds()client.groupCreate()client.groupGetById()client.groupUpdateById()client.getGroups()client.propertyCreate()client.propertyGetById()client.propertyUpdateById()client.getProperties()client.registrationCodeCreate()client.unitCreate()client.unitGetById()client.unitUpdateById()client.getUnits()client.userCreate()client.userGetById()client.userUpdateById()client.userChangePassword()client.userCreatePermission()client.userGetPermissions()client.userDeletePermission()client.userGetUtilisationPeriods()client.userCheckInToUtilisationPeriod()client.getUsers()client.getCurrentUser()client.userRelationCreate()client.userRelationDelete()client.utilisationPeriodCreate()client.utilisationPeriodDelete()client.utilisationPeriodGetById()client.utilisationPeriodUpdateById()client.utilisationPeriodCheckInUser()client.utilisationPeriodAddRegistrationCode()client.delete()client.get()client.post()client.patch()
restClient(configurationOptions?): Client
Create an client instance of the SDK.
import { restClient } from '@allthings/sdk'
const client = restClient(configurationOptions)client.createAgent()
Create a new agent. This is a convenience function around creating a user and adding that user to a property-manager's team.
const appId = '575027e58178f56a008b4568'
const propertyManagerId = '5a818c07ef5f2f00441146a2'
const username = '[email protected]'
const agent = await client.createAgent(appId, propertyManagerId, username, {
email: '[email protected]',
locale: 'en_US',
})export type MethodCreateAgent = (
appId: string,
propertyManagerId: string,
username: string,
data: PartialUser & {
readonly email: string
readonly locale: EnumLocale
},
) => UserResult// Describes the API wrapper's resulting interface
export interface IAllthingsRestClient {
readonly delete: MethodHttpDelete
readonly get: MethodHttpGet
readonly post: MethodHttpPost
readonly patch: MethodHttpPatch
// Agent
/**
* Create a new agent. This is a convenience function around
* creating a user and adding that user to a property-manager's team
*/
readonly agentCreate: MethodAgentCreate
/**
* Create agent permissions. This is a convenience function around
* creating two user permission's: one "admin" and the other "pinboard"
*/
readonly agentCreatePermissions: MethodAgentCreatePermissions
// App
/**
* Create a new App.
*/
readonly appCreate: MethodAppCreate
// Booking
/**
* Get a booking by its ID
*/
readonly bookingGetById: MethodBookingGetById
/**
* Update a booking by its ID
*/
readonly bookingUpdateById: MethodBookingUpdateById
// Group
/**
* Create a new group within a property
*/
readonly groupCreate: MethodGroupCreate
/**
* Get a group by its ID
*/
readonly groupGetById: MethodGroupGetById
/**
* Update a group by its ID
*/
readonly groupUpdateById: MethodGroupUpdateById
// ID Lookup
/**
* Map one or more externalId's to API ObjectId's within the scope of a specified App
*/
readonly lookupIds: MethodLookupIds
// Notification
/**
* Returns a collection of notifications for a given user
*/
readonly notificationsGetByUser: MethodNotificationsGetByUser
/**
* Marks all notifications of a user - until a provided timestamp (or now) - as read
*/
readonly notificationsUpdateReadByUser: MethodNotificationsUpdateReadByUser
/**
* Mark a notification as read
*/
readonly notificationUpdateRead: MethodNotificationUpdateRead
// Notification settings
/**
* Set all notification settings to default
*/
readonly notificationSettingsResetByUser: MethodNotificationSettingsResetByUser
/**
* Change user notification-settings
*/
readonly notificationSettingsUpdateByUser: MethodNotificationSettingsUpdateByUser
// Property
/**
* Create a new property
*/
readonly propertyCreate: MethodPropertyCreate
/**
* Get a property by its ID
*/
readonly propertyGetById: MethodPropertyGetById
/**
* Update a property by its ID
*/
readonly propertyUpdateById: MethodPropertyUpdateById
// Registration Code
/**
* Create a new registration code
*/
readonly registrationCodeCreate: MethodRegistrationCodeCreate
// Unit
/**
* Create a unit within a group
*/
readonly unitCreate: MethodUnitCreate
/**
* Get a unit by its ID
*/
readonly unitGetById: MethodUnitGetById
/**
* Update a unit by its ID
*/
readonly unitUpdateById: MethodUnitUpdateById
// User
/**
* Create a new User.
*/
readonly userCreate: MethodUserCreate
/**
* Get a user by their ID
*/
readonly userGetById: MethodUserGetById
/**
* Update a user by their ID
*/
readonly userUpdateById: MethodUserUpdateById
/**
* Get a list of users
*/
readonly getUsers: MethodGetUsers
/**
* Get the current user from active session
*/
readonly getCurrentUser: MethodGetCurrentUser
/**
* Change a user's password
*/
readonly userChangePassword: MethodUserChangePassword
/**
* Give a user a permission/role on an given object of specified type
*/
readonly userCreatePermission: MethodUserCreatePermission
/**
* Get a list of user's permissions
*/
readonly userGetPermissions: MethodUserGetPermissions
/**
* Delete a user a permission/role on an given object of specified type
*/
readonly userDeletePermission: MethodUserDeletePermission
/**
* Get a list of user's current utilisation - periods
*/
readonly userGetUtilisationPeriods: MethodUserGetUtilisationPeriods
/**
* Checkin a user into a Utilisation-Period with userId and
* utilisation-periodId
*/
readonly userCheckInToUtilisationPeriod: MethodUserCheckInToUtilisationPeriod
// User Relation
/**
* Creates a new user relation
*/
readonly userRelationCreate: MethodUserRelationCreate
/**
* Deletes a new user relation
*/
readonly userRelationDelete: MethodUserRelationDelete
// Utilisation Period
/**
* Create a new utilisation period within a Unit
*/
readonly utilisationPeriodCreate: MethodUtilisationPeriodCreate
/**
* Deletes a utilisation period by its id
*/
readonly utilisationPeriodDelete: MethodUtilisationPeriodDelete
/**
* Get a utilisation period by its ID
*/
readonly utilisationPeriodGetById: MethodUtilisationPeriodGetById
/*
* Update a utilisation period by its ID
*/
readonly utilisationPeriodUpdateById: MethodUtilisationPeriodUpdateById
/**
* Check-in a user to a utilisation period with the users email
*/
readonly utilisationPeriodCheckInUser: MethodUtilisationPeriodCheckInUser
}Selecting response fields (returnFields)
Many read/write methods accept an optional final returnFields argument — a
readonly string[] of serialization group names — that narrows the fields
the API returns. Fewer fields means smaller, faster responses. Under the hood it
is sent as the X-Allthings-return-fields HTTP header.
import { restClient } from '@allthings/sdk'
const client = restClient({ accessToken: '043dab7447450772example1214b552838003522' })
// Ask for only the unit's id and name
const unit = await client.unitGetById('5728e58178f56a008b45c4', [
'unit_id',
'unit_name',
])
// → { id: '5728e58178f56a008b45c4', name: 'Unit 1' }
// (no address, size, externalId, … in the response)returnFields are serialization group names, not response property names
(e.g. unit_name, not name). If none of the groups you pass overlap with what
the endpoint exposes, the hint is ignored and you get the full default payload
back.
Which methods accept it
Only endpoints whose API controller serializes with field-specific groups
support field selection — for example unitGetById / unitCreate /
unitUpdateById / getUnits, propertyGetById, groupGetById, userGetById,
getUsers, utilisationPeriodGetById, registrationCodeCreate,
ticketGetById, and userGetPermissions.
Any method whose TypeScript signature ends with returnFields?: ReturnFields
accepts it. Methods without that parameter (e.g. bookingGetById, bucketGet,
fileCreate, serviceProviderGetById, conversationGetById, and the
notification-settings methods) deliberately omit it: their endpoints serialize
with a single catch-all group, so field selection would have no effect there
(see the note below).
Finding the group names in php-prod
The group names live in the API monorepo (php-prod) as JMS serializer config.
For an entity Foo, open its serializer file:
symfony/src/Qipp/<Bundle>/Resources/config/serializer/Document.Foo.ymlEach property lists a groups: array. Pass the field-specific group (the one
named after the field) — never the catch-all *_default:
# symfony/src/Qipp/HomeBundle/Resources/config/serializer/Document.Unit.yml
Qipp\HomeBundle\Document\Unit:
exclusion_policy: ALL
properties:
id:
groups: [unit_id, unit_embedded] # ← pass 'unit_id'
name:
groups: [unit_name, unit_embedded] # ← pass 'unit_name'
externalId:
groups: [unit_external_id, unit_embedded] # ← pass 'unit_external_id'Why some endpoints don't support it. The API intersects your
returnFieldswith the serialization groups the controller passed toSerializationService::getResponse(...). When a controller passes only a single catch-all group likebooking_default(attached to every property) — or passes no groups at all — the intersection is either everything or empty, and an empty intersection falls back to the full default set. Those endpoints gain nothing fromreturnFields, which is why the SDK doesn't expose the parameter for them.To confirm what a given endpoint supports, check its controller action in
symfony/src/Qipp/<Bundle>/Controller/: the groups array passed togetResponse(...)is exactly what yourreturnFieldsare matched against. If it lists per-field groups (often via the document'sgetDefaultSerializationGroups()), field selection works; if it passes a lone*_defaultgroup, it does not.
Release management & versioning
!! DO NOT npm version !!
The Allthings SDK makes use of semantic-release which automates the whole package release workflow including:
- determining the next version number
- generating the release notes and publishing the package.
This repository is also configured to squash-merge (see here).
When you squash merge, GitHub takes the title of the PR for the squash-merge's commit subject.
By choosing a proper PR title e.g. feat: my new feature your merged PR will trigger a new release.
See semantic-releases docs for available prefixes.
Development release
Create or check out the target branch from the commit you want to release:
git checkout -b beta # or alpha / nextPush the branch to trigger the CI pipeline:
git push --force origin HEAD:beta # or alpha / nextThe pipeline will automatically run
semantic-release, which detects the branch name, bumps the version with the appropriate pre-release tag, and publishes it to npm under the matching dist-tag. Check Actions page for the release logs.Install the pre-release in another project:
npm install @allthings/cloud-toolkit@beta # or @alpha / @nextor use exact release (check versions on npm):
npm install @allthings/[email protected]Promote to stable – once the pre-release is validated, create a PR form your target branch.
Local tests
To run local tests, init the shell from devenv and use this command:
ALLTHINGS_OAUTH_CLIENT_ID='<oauth_client_id>' \
ALLTHINGS_OAUTH_CLIENT_SECRET='<oauth_client_secret>' \
ALLTHINGS_OAUTH_USERNAME='<oauth_username' \
ALLTHINGS_OAUTH_PASSWORD="<oauth_password>" \
./bin/test-ci.sh --update --log accounts,events,php
if you don't want to init the shell, please also provide next env variables to command as well:
- ALLTHINGS_ACCOUNTS_RECAPTCHA_SECRET_KEY
- SSL_PASS
Credentials could be found in dev.secrets repo.
