npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

fm-dapi

v1.0.1

Published

A NodeJS wrapper for interfacing with the Claris FileMaker Data API.

Downloads

320

Readme

fm-dapi

The fm-dapi packages provides a DapiClient object which is a TypeScript class that provides an easy-to-use interface for interacting with FileMaker's Data API. The class allows you to perform common CRUD (create, read, update, delete) operations on FileMaker records, as well as execute find requests and perform scripts.

With DapiClient, you can connect to your FileMaker database and authenticate with the Data API using your account credentials. Once authenticated, you can use the class methods to interact with your data, passing in data in the form of TypeScript objects and receiving data back in the same format.

DapiClient is designed to be simple and easy to use, with a clear and concise API that abstracts away the complexity of working with the Data API directly. It also provides error handling and logging to help you troubleshoot issues when they arise.

Installation

Using npm:

$ npm install fm-dapi

Using yarn:

$ yarn add fm-dapi

Usage

DapiClient Configuration

To use the fm-dapi, initialize the DapiClient with the credentials for your FileMaker host and database.

The client automatically handles creating sessions and maintaining session tokens. When the first request is made, a session will be created and the token will be stored. This token will be reused for as long as the session is active. Once the session expires, a new session token will be regenerated.

import {DapiClient} from 'fm-dapi' // or const {DapiClient} = require('fm-dapi')

// Set configuration
const dapiClient = new DapiClient({
    username: process.env.USERNAME,
    password: process.env.PASSWORD,
    version: "vLatest",
    host: "mydomain.com",
    database: "databaseName"
});

Additional Configurations

There are some optional arguments that are available to use.

Reattempts

If you are a using a system that sometimes has an unreliable network, it can be useful to retry an attempt if the first attempt fails. We have built-in a feature to handle this which will retry any attempts that return a network error up to a maxAttempts parameters that you can specify. This parameter defaults to 1.

Shared Sessions

If you want to have more control on how the session tokens are handled, you can provide the 'getSharedToken' and 'updateSharedToken' functions. In this case, the DapiClient won't store the session tokens but will instead call the 'getSharedToken' method and expect it to return the value of the current session token. If the session is expired, the DapiClient will create a new session token and then call the 'updateSharedToken' method passing in the new session token as the argument.

This system is useful if you have multiple apps accessing the same database and you want them all to use the same session. In this case, you can store the session token in a Redis DB and have the 'getSharedToken' read from that DB and the 'updateSharedToken' update the value in the DB.

// Set configuration
const dapiClient = new DapiClient({
    username: process.env.USERNAME,
    password: process.env.PASSWORD,
    version: "vLatest",
    host: "mydomain.com",
    database: "databaseName"
    maxAttempts: 3, // Optional. Defaults to 1.
    getSharedToken: async function() {
        // get token from DB...
        return token;
    }, // Optional
    updateSharedToken: async function(sessionToken) {
        // update token in DB with sessionToken...
    }  // Optional
});

Working with records

Creating records

To create a record, simply pass the name of the layout and an object for the field data.

const layout = "People_Create"

const hanSolo = {
  "name": "Han Solo",
  "gender": "male",
  "height": "180",
  "mass": "80",
  "hair_color": "brown",
  "skin_color": "fair",
  "eye_color": "brown",
  "birth_year": "29BBY"
}

const fmRequest = {
    "fieldData": hanSolo
}

const fmResponse = await dapiClient.createRecord(layout, fmRequest)

Getting records

To get a record or a range of records, use the getRecord and getRecords methods respectively, passing in the required arguments.

const layout = "People"
const recordId = 101

const fmResponseSingleRecord = await dapiClient.getRecord(layout, recordId)

const fmResponseRangeOfRecords = await dapiClient.getRecords(layout) // returns the first 100 records

Updating records

To update a record, pass in the layout name, recordId, and an object with the field data you would like to update.

const layout = "People_Edit"
const recordId = 1

const lukeRecord = {
  "rank": "Jedi Knight",
  "lightsaber": 'green'
}

const fmRequest = {
    "fieldData": lukeRecord
}

const editResponse = await dapiClient.editRecord(layout, recordId, fmRequest)

Deleting records

To delete a record, pass in the layout name and recordId of the record you want to delete.

const layout = "People"
const darthVaderRecordId = 2

const deleteResponse = await dapiClient.deleteRecord(layout, darthVaderRecordId)

Performing find requests

You can use the 'createFindRequest' method to easily build out and perform a find request. It provides different connector functions for different comparison operators and allows you to chain find requests by using the 'and' function. It also supports all of the normal options inside of the 'createFindRequest' method. The find won't be performed until you call the 'perform' method on it.

Here is a site of all the comparison functions.

  • is(value) // loose find
  • isEqualTo(value) // strict find
  • isLessThan(value)
  • isLessThanOrEqualTo(value)
  • isGreaterThan(value)
  • isGreaterThanOrEqualTo(value)
  • isEmpty()
  • isBetween(startValue, endValue) // search using startValue...endValue

Method 1

const layout = 'Planets'

const sort =  [
                {
                    "fieldName": "size",
                    "sortOrder": "descend"
                }
            ]           

const rebelBaseLocations = await dapiClient.createFindRequest({
            sort: sort,         // optional
            portals: [ "Rebel Leaders" ]  // optional
        })
        .where('population').isLessThan(2000).and('remoteness').is('extreme')
        .where('allegiance').isEqualTo('Rebellion')
        .omitWhere('already_searched').isEqualTo(1)
        .perform()

Method 2

You can also manually build out the query object and pass it with all of the normal options into the performFind method.

const layout = ''

const query = [
                {
                    "population": 2000,
                    "remoteness": "extreme"
                },
                {
                    "allegiance": "Rebellion"   
                },
                {
                    "already_searched": 1,
                    "omit": "true"
                }
            ]

const sort =  [
                {
                    "fieldName": "size",
                    "sortOrder": "descend"
                }
            ]           

const findResult = await dapiClient.performFind(layout, {
    query: query,
    sort: sort,         // optional
    portals: [ "Rebel Leaders" ]  // optional
})

Running FileMaker Scripts

To perform a FileMaker script, pass in the layout name, script name, and script parameter.

Please note that this method use a GET request and passes the script parameter as a URL parameter. This means that the script parameter is bound by the URL parameter character limit which can cause issues if you are trying to pass very large JSON or Base64Encoded script parameters. In this case, it would be better to run the script by including it in the request body of either a find request or a create/edit request (see https://help.claris.com/en/data-api-guide/content/run-script-with-another-request.html)

const layout = 'Space'
const script = 'Destroy Death Star'
const parameter = 'Torpedo'

const scriptResponse = await dapiClient.performScript(layout, script, parameter)

Getting metadata

Not implemented

Upload container data

Not implemented

Setting global fields

Not implemented

Miscellaneous functions

dapiClient.getHost() // returns host that the DapiClient is assigned to connect to

dapiClient.getVersion() // returns dapi version that the DapiClient is assigned to use

dapiClient.getDatabase() // returns host that the DapiClient is assigned to connect to

dapiClient.getBaseUrl() // returns baseUrl with the format `https://${host}/fmi/data/${version}/databases/${database}`

await dapiClient.getSessionToken() // returns the session token currently in use

TODO

  • [ ] Add better options for the GetRecords method
  • [ ] Add support for client-side JavaScript
  • [ ] Add unit tests
  • [ ] Add support for uploading Container Data
  • [ ] Add support for duplicating record
  • [ ] Add support for getting metadata
  • [ ] Add support for setting global fields
  • [ ] Add option for auto-logout after each request.

License

This project is licensed under the MIT License - see the LICENSE file for details