We do lots of work with FileMaker, particularly with the FileMaker Data API. We also use Ansible for lots of the deployments we do of web applications we build.
Recently we needed to put both of these things together because we needed to pull information from FileMaker and make decisions in Ansible about what needed to be done based on data in a FileMaker field.
As with most APIs the first thing we needed to do was to authenticate against FileMaker. To do that we make use of the Ansible uri
module, run as a local task.
- name: Login to the remote FileMaker server
local_action:
module: uri
url: "https://{{ filemaker_server }}/fmi/data/v1/databases/{{ filemaker_file }}/sessions"
method: POST
force_basic_auth: yes
url_username: "{{ dapi_username }}"
url_password: "{{ dapi_password }}"
return_content: yes
status_code: 200
body: ""
body_format: json
register: response
Breaking this down:
local_action: | Tell Ansible that we want to run this command locally. There’s no need to ssh into the remote server to perform an API call which we can do from anywhere. |
---|---|
module: uri | The task we want to perform uses the uri module. |
url: “https://{{ filemaker_server }}/fmi/data/v1/databases/{{ filemaker_file }}/sessions” | Define the location to connect to. We’re using two variables filemaker_server and filemaker_file so they only need to be modified in one place if things change. |
method: POST | Perform this as a post – this is required by the FileMaker Data API. |
force_basic_auth: yes | Force the URI module to use BASIC Authentication, since this is the only option supported by the FileMaker Data API. |
url_username: “{{ dapi_username }}” | The username to send, stored in an Ansible variable. |
url_password: “{{ dapi_password }}” | The password to send, stored in an Ansible variable. Make sure you’re using ansible-vault to encrypt any file containing password variables! |
return_content: yes | We want to get the result of the call back. |
status_code: 200 | We expect status code 200 – anything else will be deemed as a failure by Ansible. |
body: “” | We have to explicitly set the post body to an empty string. Anything else, including omitting the body entirely will upset the FileMaker Data API and you won’t get your token back! |
body_format: json | Even though we’re setting the body to be an empty string, we need to specify the body format as JSON so that the correct Content-Type header is sent. I agree that this seems odd given we’re sending an empty string, however this combination of settings is the only way we can get this to work! |
register: response | This tells Ansible that we want the response from the API call to be stored in the variable response. |
Next we need to extract the returned token. We’re going use set_fact
to store that as a variable for later use. Because the response we receive from the FileMaker Data API is a JSON object we can access the token itself using ‘dot’ notation.
- name: Extract the token from the response
set_fact:
dapi_token: "{{ response.json.response.token }}"
Now that we have the token we can begin communicating with the FileMaker Data API. Again we use the uri
module running as a local action.
Many of the parameters are the same as logging in, but we also need to send the token back in an Authorization header. In the code below we’re getting the record from the Version layout, which has (internal FileMaker) record ID 1. If you didn’t know exactly which record you needed, you could also perform a find query here – see the documentation for the FileMaker Data API for further details (that can be easily accessed from https://your.fms.com/fmi/data/apidoc).
- name: Get the remote interface version data
local_action:
module: uri
url: "https://{{ filemaker_server }}/fmi/data/v1/databases/{{ interface_file }}/layouts/Version/records/1"
method: GET
return_content: yes
status_code: 200
headers:
Authorization: "Bearer {{ dapi_token }}"
register: response
Again we’re storing the response from the API call in the response
variable. For our purposes we needed the content of the VersionBuild
field. Again the response is a JSON object so we can traverse that tree to the data point we need.
- name: Set remote build version
set_fact:
remote_build: "{{ response.json.response.data[0].fieldData.VersionBuild | int }}"
tags:
- api
You’ll note that we use data[0]
because even though we’re only requesting a single record (by record ID) the FileMaker Data API still returns an array of record objects.
At this stage we don’t need to write data back to FileMaker but that would also be possible to do using the same techniques above, for example to write a log record recording that a deployment had been completed.