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.
Using npm:
$ npm install fm-dapi
Using yarn:
$ yarn add fm-dapi
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"
});
There are some optional arguments that are available to use.
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.
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
});
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)
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
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)
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)
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
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()
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
})
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)
Not implemented
Not implemented
Not implemented
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
- [ ] 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.
This project is licensed under the MIT License - see the LICENSE file for details