syncables
v0.11.0
Published
Generate sync engine code from OpenAPI specifications
Readme
Syncables
This repository contains a sync engine that can be used to download (and in the future also update) a collection of objects from an API. It can be configured declaratively by extending the OpenAPI spec.
Find the path that can be used to fetch a (paged) collection of items. This will typically look something like this:
paths:
/widgets:
get:
parameters:
- description: Token specifying which result page to return. Optional.
in: query
name: pageToken
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/CalendarList"
components:
schemas:
CalendarList:
properties:
results:
items:
properties:
backgroundColor:
type: string
type: array
nextPageToken:
description: Token used to access the next page of this result. Omitted if no further results are available.
type: string
type: objectUnder paths['/widgets']['get']['responses']['200']['content']['application/json'], add an object syncable, in which you can specify:
name: astringdescriptor of the collection, e.g."widgets"paginationStrategy: one ofpageNumber,offset,pageToken,dateRange,rangeHeader, orconfirmationBased.query: an object containing query parameters to add in addition to the pagination-related onesitemsPathInResponse: path within the response body schema, as an array of strings, that contains the array of items (default:[]for the response body root)defaultPageSize: tell Syncable how many items per page (max) to expect by defaultforcePageSize: if possible, let Syncable tell the API which page size to use (not applicable to pagination strategydateRange)- when using
forcePageSize, you can addforcePageSizeParamInQueryif it's notpageSize(not applicable to pagination strategiesdateRangeandrangeHeader). - for a
pageNumberpagination strategy, you can addpageNumberParamInQueryif it's notpage. - for an
offsetpagination strategy, you can addoffsetParamInQueryif it's notoffset. - for a
pageTokenpagination strategy, you can addpageTokenParamInQueryif it's notpageTokenandpageTokenPathInResponseif it's not['nextPageToken'] - for a
dateRangepagination strategy, you can addstartDateParamInQueryif it's notstartDate,endDateParamInQueryif it's notendDate,startDateif it's not'20000101000000', andendDateif it's not'99990101000000' - for a
confirmationBasedpagination strategy,confirmOperation.pathandconfirmOperation.method. Then at that operation, you can addconfirmOperation.pathTemplate. idFieldto indicate which property of response items is used as the unique identifier (currently only used for confirmationBased pagination).
Usage
Create the OAD
You start with an OAD, for instance one from here. Probably the API you want to use is not specifying syncables yet, so you'll need to add those yourself using an overlay, something like the ones you see here. To compute the effect of the overlay you can run a command like:
./node_modules/.bin/overlayjs --openapi ./openapi/oad/acube-peppol.yaml --overlay ./openapi/overlay/acube-peppol-overlay.yaml > openapi/generated/acube.yamlGenerate the type
Assuming you're working in TypeScript, you can benefit from generating types from the OAD, like so:
npx openapi-typescript openapi/generated/acube.yaml -o ./src/types/acube.d.tsInstall syncables
Depending on your preferred package manager, you can run something like this to install syncables from npm:
pnpm install syncablesWrite your code
Now you have the AOD with the definition of the syncable, and the type for the items you will sync, you can write code like this:
import { readFileSync } from 'fs';
import { components } from './src/types/google-calendar.js';
import { Syncable } from 'syncable';
type Entry = components['schemas']['CalendarListEntry'];
const specStr = readFileSync('./openapi/generated/google-calendar.yaml').toString();
const syncable = new Syncable<Entry>({
specStr,
syncableName: 'widgets',
authHeaders: {
Authorization: `Bearer ${process.env.GOOGLE_BEARER_TOKEN}`
},
dbConn: 'postgresql://syncables:syncables@localhost:5432/db_unit_tests'
});
await syncable.fullFetch();You can use the showcase-google-calendar branch of this repo to run a simple OAuth client that can obtain a value for the GOOGLE_BEARER_TOKEN environment variable.
Development
git clone https://github.com/tubsproject/syncables
cd syncables
pnpm install
pnpm generate
pnpm build
pnpm test
pnpm prettier
pnpm login
pnpm publishUsage
docker compose up -d
# run your code that calls syncable.fullFetch();
docker exec -it db psql postgresql://syncables:syncables@localhost:5432/db_unit_tests -c "\d+"Acknowledgements
The __tests__/integration/mock-server' folder is a copy of [@scalar/mock-server`](https://github.com/scalar/scalar/blob/main/packages/mock-server/src) - thanks Scalar!
