Forge Function - How to reference to handler file in sub-directory

I have a Forge app with this structure:

src
 |-- admin
 |     |-- index.js
 |-- panel
       |-- index.js

How can I define two functions which refer to the handler from those sub-directory, instead of put 2 js files to the src?
The below code does not work for me.

function:
  - key: admin-page-resolver
    handler: admin/index.handler
  - key: panel-handler
    handler: panel/index.run

Thanks!

1 Like

Based on the error message I see when trying to repro it, I don’t think you can do any sort of pathing in your app’s manifest.yml:

function handler property ‘test/best.handler’ must be in format <module>.<function>

However, a workaround for this might be to have a top-level module that you import all of your sub-modules and functions into.

So your structure becomes:

src
 | -- index.js
 |-- admin
 |     |-- index.js
 |-- panel
       |-- index.js

And then both admin/index.js and panel/index.js export the functions you want to make use of:

export const handler = resolver.getDefinitions();

And your top-level src/index.js imports them:

import { handler } from 'admin';

export const handler;
6 Likes

Thanks, @bentley,

It has been more than a month since this question, and I actually went with that same solution as your answer.

Cheers

3 Likes

Hi,

Can you please give little more explanation on how exporting the admin/index.js into index.js.
with a little structure format would be helpful with basic example.

Thanks!

If you have multiple modules then it usually make sense to separate your backend functions out into their own files - one for each module for ease of maintenance.

Here’s an example manifest with two modules: macro and confluence:spacePage.

The entrypoint for the functions are index.macroHandler and index.spacePageHandler respectively.

modules:
  macro:
    - key: forge-starter-app-hello-world-macro
      resource: macro
      render: native
      resolver:
        function: macro-resolver
      title: forge-starter-app
  confluence:spacePage:
    - key: forge-starter-app-space-page
      resource: spacePage
      render: native
      resolver:
        function: space-page-resolver
      route: forge-starter-app-space-page
      title: forge-starter-app
  function:
    - key: macro-resolver
      handler: index.macroHandler
    - key: space-page-resolver
      handler: index.spacePageHandler
resources:
  - key: macro
    path: src/frontend/macro.jsx
  - key: spacePage
    path: src/frontend/space-page.jsx
app:
  id: ari:cloud:ecosystem::app/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
permissions:
  scopes:
    - read:confluence-user

In your app’s src directory, you would have a folder called handlers which contains the functions for each module.

└── src
    ├── index.js
    ├── handlers
    │   ├── macro.js
    │   └── spacePage.js

src/handlers/macro.js

import Resolver from "@forge/resolver";

const resolver = new Resolver();

resolver.define("macro-function", () => {
  return "Hello, World!";
});

export const macroHandler = resolver.getDefinitions();

src/handlers/spacePage.js

import Resolver from "@forge/resolver";

const resolver = new Resolver();

resolver.define("space-page-function", () => {
  return "Hello, World!";
});

export const spacePageHandler = resolver.getDefinitions();

And finally, in src/index.js you need to export these two handlers.

export { macroHandler } from "./handlers/macro";
export { spacePageHandler } from "./handlers/spacePage";

:warning: This is important because Forge requires that we point to our backend functions using the file.function format e.g. index.macroHandler and index.spacePageHandler.

3 Likes

Thanks, @rcsr ,

This helped me lot.

Cheers

1 Like

Thanks @rcsr for this solution.
In manifest.yml, I think you meant

modules:
  macro:
    - key: forge-starter-app-hello-world-macro
      resource: macro
      render: native
      resolver:
        function: macro-resolver # instead of space-page-resolver
      title: forge-starter-app

In How to split resolvers in multiple files? - #3 by BertrandDrouhard1, there is a solution to also have share files and avoid conflicts. The mix of your solution and this solution seems to solve the whole situation!

2 Likes

Good catch! Glad it was helpful.

1 Like

Hey @BentleyCook, this way can I make directory structure like backend/src and frontend/src ?
In ‘backend’ folder store resolvers and in ‘frontend’ folder - frontend code?

In that case index.js would be in backend/src/index.js

Hi Oleh,

Unfortunately having sources not under the src root directory isn’t supported. Please upvote FRGE-422 to show it’s important to you, and start a new thread if you have further questions!