Skip to content


Repository files navigation

Go Report Card


This library provides access to FileMaker Server using XML Web publishing.

Initially the library was a port of, but it evolved a lot since.

In Production

The library is used in production to proxy the calls from API server to FileMaker database.


FileMaker differs Postgres or MySQL, so we cannot run docker and test the library in CI/CD. Maybe we could run EC2 with Windows and install FileMaker Server on it to run the integration test, yet it seems a bit overkill and very time-consuming at this moment.


Run the command below in the root directory of your project:

go get

Then import the lib in your code:

import ""


Full example

package main

import (
	fm ""

// config represents all the configuration we need in order to
// create a new FMConnector and establish the connection with 
// FileMaker database 
type config struct {
	FmHost         string `split_words:"true" required:"true"`
	FmUser         string `split_words:"true" required:"true"`
	FmPort         string `split_words:"true" required:"true"`
	FmDatabaseName string `split_words:"true" required:"true"`
	FmPass         string `split_words:"true" required:"true"`

type postStore struct {
	fmConn *fm.FMConnector
	dbName string

type Post struct {
	Author  string `json:"Author"`
	Title   string `json:"Title"`
	Content string `json:"Content"`

func (p *Post) Populate(record *fm.Record) {
	p.Author = record.Field("author")
	p.Title = record.Field("title")
	p.Content = record.Field("content")

func main() {
	var conf = &config{}
	err := envconfig.Process("", conf)
	if err != nil {

	fmConn := fm.NewFMConnector(conf.FmHost, conf.FmPort, conf.FmUser, conf.FmPass)
	store := postStore{fmConn: fmConn, dbName: conf.FmDatabaseName}

	posts, err := store.GetAllPosts(fmConn)
	if err != nil {


func (ps *postStore) GetAllPosts() ([]Post, error) {
	var posts []Post

	q := fm.NewFMQuery(ps.dbName, "posts_list_layout", fm.FindAll)
	fmset, err := ps.fmConn.Query(q)
	if err != nil {
		return posts, errors.New("failed to get posts")

	// Populate it with record
	for _, r := range fmset.Resultset.Records {
		p := Post{}

		b, _ := r.JsonFields()
		_ = json.Unmarshal(b, &p)
		posts = append(posts, p)

	return posts, nil

Get a single record

    q := fm.NewFMQuery(databaseName, layout_name, fm.Find)
        fm.FMQueryField{Name: "field_name", Value: "001", Op: fm.Equal},

Check if the error is FileMaker specific one

    fmSet, err := fmConn.Query(q)
    if err != nil {
        if err.Error() == fmt.Sprintf("FileMaker_error: %s", fm.FileMakerErrorCodes[401]) {
            // your code
        // else do something

Create a record

    q := fm.NewFMQuery(databaseName, layout_name, fm.New)
        fm.FMQueryField{Name: "field_name", Value: "some_value"},
    fmSet, err := fmConn.Query(q)

Sort the records

    q.WithSortFields(fm.FMSortField{Name: "some_field", Order: fm.Descending})

Update a record

Your object should have FileMaker record id to update record in database. Please see more in FileMaker documentation.

    q := fm.NewFMQuery(databaseName, layout_name, fm.Edit)
        fm.FMQueryField{Name: "field_name", Value: "some_new_value"},

Run a script

    // SCRIPT_DELIMITER can be '|', '_' or any other symbol that will be
    // parsed on FileMaker side to get all the parameters from the string
    q.WithPostFindScripts(SCRIPT_NAME, strings.Join([]string{param_1, param_2, param_3}, SCRIPT_DELIMITER))