Documentation
    Preparing search index...

    Documentation

    Datalynk Client Library

    pipeline status


    Datalynk client library to integrate JavaScript clients with the Datalynk API.

    1. Install the client library
    npm install --save @auxilium/datalynk-client
    
    1. Optional: Build Datalynk models
    $ npx datalynk-models
    Output (src/models):
    Spoke: spoke
    Login: username
    Password: ********
    1. Create an API object & start making requests
    import {API} from '@auxilium/datalynk-client';

    const api = new API('https://spoke.auxiliumgroup.com');
    const resp = await api.request({'$/auth/current':{}});

    Full API Documentation

    Integration

    This library is written with vanilia JS & has no framework dependencies allowing easy integration with any front-end website. Here is some boilerplate to get you going:

    File: /src/services/datalynk.service.ts

    import {Injectable} from '@angular/core';
    import {Api, Slice} from '@auxilium/datalynk-client';
    import {environment} from '../environment/environment';
    import {Contact} from '../models/contact';
    import {Slices} from '../models/slices';

    declare global {
    interface Window {
    api: Api;
    }
    }

    @Injectable({providedIn: 'root'})
    export class DatalynkApi extends Api {
    contacts!: Slice<Contact>;

    constructor() {
    // Create API object & expose to window
    super(environment.api, {/* options */});
    window.api = this;

    // Handle logging in
    this.auth.handleLogin('spoke', {/* login UI options */});

    // Create store to cache slice data
    this.contacts = this.slice<Contact>(Slices.Contact);
    }
    }

    File: /src/services/datalynk.service.ts

    import {Api} from '@auxilium/datalynk-client';
    import {environment} from '../environment/environment';
    import {Contact} from '../models/contact';
    import {Slices} from '../models/slices';

    // Create API object & expose to window
    export const api = window.api = new Api(environment.api, {/* options */});

    // Handle logging in
    api.auth.handleLogin('spoke', {/* login UI options */});

    // Create store to cache slice data
    export const contacts = api.slice<Contact>(Slices.Contact);

    File: /index.html

    <script type="module">
    import {Api} from '@auxilium/datlaynk-client/dist/index.mjs';

    // Create API object & expose to window
    var api = new Api('https://spoke.auxiliumgroup.com', /* options */);

    // Handle logging in
    api.auth.handleLogin('spoke', {/* login UI options */});

    // Create store to cache slice data
    var contacts = api.slice(12345);
    </script>

    Build Models

    This library comes with a command line tool for developers to automatically create Typescript models from the Datalynk metadata.

    This takes most of the manual labour out of manually mapping the data & provides type safety.

    1. Simply run the tool:
    $ npx datalynk-models
    Output (src/models):
    Spoke: spoke
    Login: username
    Password: ********
    1. Import models:
    import {Slices} from 'models/slices'; // Import slices map
    import {Contact} from 'models/contact'; // Import model for slice we will be using

    const contacts: Contact[] = await api.slice<Contact>(Slices.Contact)
    .select()
    .rows().exec();

    Authentication

    Login as the guest account

    const guest = await api.auth.loginGuest();
    console.log(api.auth.isGuest()) // True

    This library comes with some logic to automatically handle the login flow & should be called at the startup of your application:

    1. It will check the URL for a token param: ?datalynkToken=...
    2. It will check the localStorage for a saved token
    3. It will prompt the user to login via UI
    4. Reload page if token changed
    await api.auth.handleLogin('spoke', {
    background: 'url("...")', // CSS URL or hex color
    color: '#ff0000', // hex color
    title: '<img alt="logo" src="..." />', // text or HTML
    textColor: '#ffffff' // Color of title text
    });

    Alternatively you can manage the login prompt manually:

    const prompt = api.auth.loginPrompt('spoke', options);
    await prompt.wait; // Wait for the user to login/close the prompt
    prompt.close(); // Close prompt manually

    Manually login programmatically:

    const user = await api.auth.login('spoke', 'username', 'password', '2faCode');
    

    Chain Requests

    Multiple requests can be chained together to run them in order. The last request's response will be returned

    const report = await api.chain({'$/auth/current': {}}, api.slice(12345).select().rows());
    

    All results can be returned together by using the chainMap

    const {user, report} = await api.chainMap({
    user: {'$/auth/current': {}},
    report: api.slice(52131).select().rows()
    });

    Slice Engine

    This library comes with LINQ style query language to help make interacting with Slices easier by providing types & intelisense.

    // Get a single record
    const row = await api.slice<T>(12345)
    .select(12345)
    .row().exec();

    // Get all slice records
    const rows = await api.slice<T>(12345)
    .select()
    .rows().exec();

    // Advanced queries
    const rows = await api.slice<T>(12345)
    .select()
    .fields({'field1': 'field2'})
    .where('field1', '<', 0)
    .or()
    .where({field1: 0, field2: false})
    .order('field2', true) // ascending
    .limit(10)
    .rows().exec();
    const count = await api.slice(12345)
    .count()
    .where({field1: 'value'})
    .count().exec();
    // Insert record
    const key = await api.slice<Contact>(12345)
    .insert({first: 'Bilbo', last: 'Baggins'})
    .id().exec();

    // Insert multiple rows
    const keys = await api.slice<Contacts>(12345)
    .insert([
    {first: 'Darth', last: 'Vader'},
    {first: 'John', last: 'Snow'}
    ])
    .ids().exec();
    // Update a record
    const success = await api.slice(12345)
    .update({id: 1, first: 'James', last: 'Kirk'})
    .id().exec();

    // Update multiple rows with where
    await api.slice(12345)
    .update({evil: true})
    .where({first: 'Darth'})
    .ids().exec();
    // Delete a record
    const success = await api.slice(12345)
    .delete(12345)
    .id().exec();

    // Dlete multiple rows with where
    await api.slice(12345)
    .delete()
    .where({first: 'Darth'})
    .ids().exec();

    Sockets

    The socket can have it's endpoint override or be turned off by setting it to false:

    const api = new Api('https://spoke.auxiliumgroup.com', {
    socket: false, // Disable
    // socket: 'http://localhost:3000', // Override
    });

    The Slice Engine's cache can be synced with the server & subscribed to using RXJS:

    // Create cache/store
    const contacts = api.slice<Contact>(Slices.Contact);

    // Enable syncing
    contacts.sync();

    // Use RXJS to listen for events
    contacts.sync().pipe(...).subscribe((cache: Contact[]) => {...});
    // Or using Angular templates
    '{{ contacts.sync() | async }}'

    // Disable syncing
    contacts.sync(false);

    Alternatively socket events can be listened to directly using callbacks:

    api.socket.sliceEvents(123, callbackFn(event)); // Listen to a specific slice
    api.socket.addListener(callbackFn(event)); // listen to all socket events

    Uploads

    A file URL can be created from the file ID

    const url = api.files.get(12345);
    

    Uploading files to datalynk is done by first uploading the file as form-data & then creating a reference to the upload ID in a slice.

    // Get files from file input
    const files = document.querySelector('#upload').files;

    // Upload a file & associate it with a record in one call
    api.files.upload(files, {slice: 12345, row: 1234, field: 'abc'});
    // OR upload a file on its own
    api.files.upload(files).then(uploaded => {
    // Associate file with a record manually
    const slice = 12345, row: 123;
    api.files.associate(uploaded.map(r => r.id), slice, row, 'field');
    });