fm-dapi
v1.0.1
Published
A NodeJS wrapper for interfacing with the Claris FileMaker Data API.
Downloads
320
Maintainers
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