Skip to main content

Extending Otto's REST API

You can extend Otto's express.js http server with a custom Router that will mount at https://<otto-server>:3030/extensions/. These functions can be used to run any JavaScript functions on your server. You could use this like a simple Lambda or cloud function, or add additional automation hooks into your server. For example, you could add a POST endpoint that would commit a FileMaker file to a git repository.

This feature requires a full license of Otto.


This is an advanced feature. You should understand how to write an express.js style Router. If your extensions have errors, they could make all of Otto's features unavailable. You are responsible for making sure that your functions are secure and that they operate correctly.

How it works

Otto's API is based on Feathers.js. Feathers is built on top of express.js, and can use express routers.

If you add a router.js file to OttoFolder/config/extensions/router.js, Otto will attempt to load it as an xpress.js router and mount it at https://<otto-server>:3030/extensions/.

The file should export a function that takes an Express.js Router as a parameter. You can then add request handlers to the router as you would for a normal express.js app. In the example below, we are mounting a GET request to https://<otto-server>:3030/extensions/ping/:person.

module.exports = (router) => {
router.get("/ping/:person", (req, res, next) => {
res.json({ msg: "pong!", person: req.params.person });

When a GET request is made to https://<otto-server>:3030/extensions/ping/:brad, the route will responds with:

{ "msg": "pong!", "person": "brad" }

Pre-loaded modules

There are several modules and functions that Otto loads into the Global space of the router.js OttoFolder/config/extensions/router.js

  • errors - @feathers/errors
  • fmsDocumentsPath - a function that returns the FileMaker Server documents path
  • fmsLogsPath - a function that returns the FileMaker Server logs path
  • multer - middleware for parsing multiparty/form-data
  • createFmsDocsStorage - a function that will create a multer document storage function

Authentication is up to you

Otto will parse a Basic Auth user, if there is one, and put in req.user, but it doesn't enforce a particular user or password. Here is an example of how you might use basic auth:

router.get("/ping/:person", (req, res, next) => {
if ( !== "joe" || user.pass === "1234") {
return next(
errors.NotAuthenticated("you aren't joe, or you don't know your password")
res.json({ msg: "pong!", person: req.params.person });

You can use any kind of logic you want to determine if a request should go through, or if it should return a 401 Unauthorized error. In the example above we see how you can easily create a 401 response by using the built in errors module. returning next(error) is the most common way of signalling to express that this should be an error. You can also just throw the error as well.

throw errors.NotAuthenticated("you aren't joe, or you don't know your password")

Using other modules

You can use modules from npm and of your own creation. But you can only import from within the Otto/config.exenstions directory. You cannot pull modules from outside of that directory. That means that your node_modules folder must go in there as well.


Any time you change anything in the extensions folder, you will have to restart Otto.