Override default routes in express/nodejs

Feature(s) impacted

Overriding default behaviour of forest admin.

Context

I’m using nodejs backend in express framework and postgresql as database, using sequelize ORM.

I created a project in ForestAdmin and using own backend server and I’m able to connect backend and Forest Admin UI panel.

I’ve installed these forest admin dependencies in my nodejs/express project :
@forestadmin/agent”: “^1.8.13”,
@forestadmin/datasource-sequelize”: “^1.3.1”

I want to upload an image in AWS S3 bucket and save the location url in the database. I want this process to happen through Forest Admin panel while attaching and uploading an image. I also want to enable Forest Admin authentication in the backend. (Note: smart field is not desired, please suggest only route overriding.)

I went through this doc but unable to get any help: Override a route - Developer guide

Please help me with some nodejs code example.

Hi,

I noticed that you have shared documentation regarding our previous JavaScript agent. However, the documentation you should refer to is this link for our new Node.js agent.

Please note that the Node.js backend doesn’t support route overriding. If you intend to upload images to S3, you can utilize this plugin.

Regarding your statement “I want to enable Forest Admin authentication,” could you please clarify what you mean by that?

There is no aws plugin available as mentioned in the document:

I used this and followed the docs.

Here’s the output I got:

===== An exception was raised =====
POST /Causes?{
 timezone: Asia/Calcutta
}

Body {
 data: {
  attributes: {
   cause_image: data:image/png;name=Screenshot%202023-05-03%20at%207.59.57%20PM.png;base64,iVBORw0KGgoAAGgCPwJER/kD48LkPXyQSHkvw6z8qsDyJD1FspG5IAnEOeBcJAL7yWyUcJhb4ngMWQE......... <base64 string>,
   cause_title: Title,
   conversion_rate: 10,
   conversion_rate_passive: 5,
   factor: 1,
   is_active: false,
   is_completed: false,
   is_premium_cause: false,
   is_visible_on_website: false,
   min_distance: 1,
   show_conversion_rate_icon: false
  },
  relationships: {
   CauseCategory: {
    data: {
     type: CauseCategories,
     id: 5
    }
   }
  },
  type: Causes
 }
}

 UnknownError 

InvalidArgument: UnknownError
    at throwDefaultError (/Users/girjeshsingh/Desktop/Files/Impact/Push/impact-node/node_modules/@aws-sdk/smithy-client/dist-cjs/default-error-handler.js:8:22)
    at /Users/girjeshsingh/Desktop/Files/Impact/Push/impact-node/node_modules/@aws-sdk/smithy-client/dist-cjs/default-error-handler.js:18:39
    at de_PutObjectCommandError (/Users/girjeshsingh/Desktop/Files/Impact/Push/impact-node/node_modules/@aws-sdk/client-s3/dist-cjs/protocols/Aws_restXml.js:5701:12)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async /Users/girjeshsingh/Desktop/Files/Impact/Push/impact-node/node_modules/@aws-sdk/middleware-serde/dist-cjs/deserializerMiddleware.js:7:24
    at async /Users/girjeshsingh/Desktop/Files/Impact/Push/impact-node/node_modules/@aws-sdk/middleware-signing/dist-cjs/awsAuthMiddleware.js:14:20
    at async /Users/girjeshsingh/Desktop/Files/Impact/Push/impact-node/node_modules/@aws-sdk/middleware-retry/dist-cjs/retryMiddleware.js:27:46
    at async /Users/girjeshsingh/Desktop/Files/Impact/Push/impact-node/node_modules/@aws-sdk/middleware-flexible-checksums/dist-cjs/flexibleChecksumsMiddleware.js:58:20
    at async /Users/girjeshsingh/Desktop/Files/Impact/Push/impact-node/node_modules/@aws-sdk/middleware-logger/dist-cjs/loggerMiddleware.js:7:26
    at async Client.save (/Users/girjeshsingh/Desktop/Files/Impact/Push/impact-node/node_modules/@forestadmin/plugin-aws-s3/dist/utils/s3.js:46:9)
===================================

Can you provide us with the customization code you added?
(the section with the settings provided to collection.use())

I want to upload an image to the server, save it to AWS and store its url in the database.
Here’s the code snippet below.

import { createAgent } from '@forestadmin/agent';
const { createSequelizeDataSource } = require('@forestadmin/datasource-sequelize');
import { createFileField } from '@forestadmin/plugin-s3';
const db = require('./models');
const { sequelize } = db;

const agent = createAgent({
  authSecret: process.env.FOREST_AUTH_SECRET,
  envSecret: process.env.FOREST_ENV_SECRET,
  isProduction: process.env.NODE_ENV === 'production',
}).addDataSource(createSequelizeDataSource(sequelize))
  .customizeCollection('Causes', collection =>
    collection.use(createFileField, {
      fieldname: 'cause_image',
      storeAt: (recordId, originalFilename) => `accounts/${recordId}/${originalFilename}`,
      deleteFiles: true,
      readMode: 'url',
      acl: 'public',
      aws: {
        accessKeyId: 'AKIA....',
        secretAccessKey: 'DUwsm....',
        region: 'ap-south-1',
        bucket: 'bucket_name',
      },
    }),
  )
  .mountOnExpress(app).start();

I just checked S3 documentation.
public does not seems to be a valid value for ACL.

Valid values are “authenticated-read”, “aws-exec-read”, “bucket-owner-full-control”, “bucket-owner-read”, “private”, “public-read”, “public-read-write”.

Can you change it to public-read ?

acl: 'public-read',

Thanks. It worked.
However, I faced this difficulty.

Instead of S3 object url, the forest saves this url

https://my.test.bucket.s3.async () => { if (typeof region === "string") { return (0, getRealRegion_1.getRealRegion)(region); } const providedRegion = await region(); return (0, getRealRegion_1.getRealRegion)(providedRegion); }.amazonaws.com/photos/causes/Walk-to-Educate/cause_image/cause1542896909.jpg

But I want it to be like this:

https://s3.ap-south-1.amazonaws.com/my.test.bucket/forest/Screenshot+2023-05-03+at+8.00.02+PM.png

Also it’s getting saved in the database as:

forest/image.png

Can I add the required prefix (https://s3.ap-south-1.amazonaws.com/my.test.bucket/) while uploading the image?

Looks like a bug!

I’ll try to replicate this and come back to you.