Creating project - Waiting for the backend to run

Hello,

I am trying to create a new Forest Admin project. It is called qms-test for now.
As a datasource I used Express / Sequelize.

I did everything what is written in the next step.

  1. npm install forest-express-sequelize
  2. Initialize Forest Admin
  3. Configure environments
  4. I am using cors and so I put is as my middleware:

The I ran my backend on the port 3000. And I see it working, since I can approach that through the browser.

My code in app.js looks like this:

const express = require("express");
const cors = require("cors");
const dotenv = require("dotenv");
const path = require("path");
const Sequelize = require("sequelize");
const sequelize = require("./utils/db");

const forest = require("forest-express-sequelize");
const connection = new Sequelize(
  `postgres://admin:password@localhost:5432/postgres-qms-forest`
);

dotenv.config();

const app = express();
const PORT = 3000;
app.use("^(?!forest/?$).*", cors());

forest
  .init({
    envSecret: process.env.FOREST_ENV_SECRET,
    authSecret: process.env.FOREST_AUTH_SECRET,
    objectMapping: Sequelize,
    connections: { default: connection },
  })
  .then((FAMiddleware) => {
    app.use(FAMiddleware);
  });

Console still has an error:
Access to fetch at ‘http://localhost:3000/forest’ from origin ‘https://app.forestadmin.com’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

Structure of my project looks as follows:

I just created that empty folder forest, since I was getting an error:

[forest] :deciduous_tree::deciduous_tree::deciduous_tree: Your configDir ("/Users/vaclav/javascript/qms/forest") does not exist. Please make sure it is set correctly.

Don’t you have any idea, please, how to fix this?

Thank you very much!

Vaclav

Hello @Vaclav,

Which version of forest-express-sequelize are you using ? Can you also share your project name ?

Regards,
Morgan

Hey @Vaclav,

I see that you configure your connexion only using a sequelize connection. Do note that the connection you want to provide to ForestAdmin should be initialised with the models you want to work with.

Here’s some documentation on how to define Sequelize models !

const sequelizeConnection = new Sequelize(
  `postgres://admin:password@localhost:5432/postgres-qms-forest`
);

// Example of model definition
sequelizeConnection.define('User', {
  // ... (attributes)
});

Let me know if it help.

Regards,
Morgan

Hey @morganperre,
thank you for you help, I really appreciate that. However, I am still a bit confused.
In you interactive tutorial by setting up the backend, you are talking about connection.
Check this screenshot:

You are talking about "Connection that should be initialised"? What do you mean with that, please? Initialised can be each singe model, but not connection. Or I am wrong?

Connection is described here:

But according to that, connection can’t be initialised.

Secondly, I also watched you video here: Express integration for Forest Admin
Could you please briefly tell me, what is done in 1min 12s of that video on that page? What exactly are you importing from the folder models?

Thank you,
Vaclav

And btw., I have sequelize module controllerAdmin
image

This model is synced and then the server starts listening on the port 3000.

Thank you

Hey @Vaclav,

Yes, I agree the wording is bad. I’ve already transmit your feedback to our team. So the connection is a sequelize instance with a working connection to a database and with all models (Creating an instance) you want to work with.

The connection you want to provide to ForestAdmin should be initialised with the models you want to work with. So you create a connection to your DB then you define models for this connection.

It the file that we use to handle connections and to define/import/require models (when you use the forest-cli those are automatically generated by making CRUD (introspection) on your DB).
I think your file …/utils/db is meant to do the same in your case. Can your share the content of this file ?

  • :books: I’ll give you a concret example I use myself.

1. A file that describe connections and load all models in the folder /models

models/index.js Here we define connections to the DB using environment variable DATABASE_URL_DEFAULT

const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');

const databasesConfiguration = [{
  name: 'default',
  modelsDir: path.resolve(__dirname, '../models'),
  connection: {
    url: process.env.DATABASE_URL_DEFAULT,
    options: {
     pool: { maxConnections: 10, minConnections: 1 },
     dialectOptions: {},
    },
  },
}];

const connections = {};
const db = {};

databasesConfiguration.forEach((databaseInfo) => {
  const connection = new Sequelize(databaseInfo.connection.url, databaseInfo.connection.options);
  connections[databaseInfo.name] = connection;

  const modelsDir = databaseInfo.modelsDir || path.join(__dirname, databaseInfo.name);
  fs
    .readdirSync(modelsDir)
    .filter((file) => file.indexOf('.') !== 0 && file !== 'index.js')
    .forEach((file) => {
      try {
        const model = connection.import(path.join(modelsDir, file));
        db[model.name] = model;
      } catch (error) {
        console.error(`Model creation error: ${error}`);
      }
    });
});

Object.keys(db).forEach((modelName) => {
  if ('associate' in db[modelName]) {
    db[modelName].associate(db);
  }
});

db.objectMapping = Sequelize;
db.connections = connections;

module.exports = db;

2. Then we define models, one by file

models/comments.js

// Learn how here: https://docs.forestadmin.com/documentation/v/v8/reference-guide/models/enrich-your-models
module.exports = (sequelize, DataTypes) => {
  const { Sequelize } = sequelize;
  // This section contains the fields of your model, mapped to your table's columns.
  // Learn more here: https://docs.forestadmin.com/documentation/v/v8/reference-guide/models/enrich-your-models#declaring-a-new-field-in-a-model
  const Comments = sequelize.define('comments', {
    body: {
      type: DataTypes.STRING,
      allowNull: false,
    },
  }, {
    tableName: 'comments',
    timestamps: false,
  });

  // This section contains the relationships for this model. See: https://docs.forestadmin.com/documentation/v/v8/reference-guide/relationships#adding-relationships.
  Comments.associate = (models) => {
    Comments.belongsTo(models.posts, {
      foreignKey: {
        name: 'postIdKey',
        field: 'post_id',
      },
      as: 'post',
    });
    Comments.belongsTo(models.users, {
      foreignKey: {
        name: 'userIdKey',
        field: 'user_id',
      },
      as: 'user',
    });
  };

  return Comments;
};

models/posts.js

// Learn how here: https://docs.forestadmin.com/documentation/v/v6/reference-guide/models/enrich-your-models
module.exports = (sequelize, DataTypes) => {
  const { Sequelize } = sequelize;
  // This section contains the fields of your model, mapped to your table's columns.
  // Learn more here: https://docs.forestadmin.com/documentation/v/v6/reference-guide/models/enrich-your-models#declaring-a-new-field-in-a-model
  const Posts = sequelize.define('posts', {
    title: {
      type: DataTypes.STRING,
      allowNull: false,
    },
  }, {
    tableName: 'posts',
    timestamps: false,
  });

  // This section contains the relationships for this model. See: https://docs.forestadmin.com/documentation/v/v6/reference-guide/relationships#adding-relationships.
  Posts.associate = (models) => {
    Posts.belongsTo(models.users, {
      foreignKey: {
        name: 'userIdKey',
        field: 'user_id',
      },
      as: 'user',
    });
    Posts.hasMany(models.comments, {
      foreignKey: {
        name: 'postIdKey',
        field: 'post_id',
      },
      as: 'comments',
    });
  };

  return Posts;
};

models/users.js

// Learn how here: https://docs.forestadmin.com/documentation/v/v6/reference-guide/models/enrich-your-models
module.exports = (sequelize, DataTypes) => {
  const { Sequelize } = sequelize;
  // This section contains the fields of your model, mapped to your table's columns.
  // Learn more here: https://docs.forestadmin.com/documentation/v/v6/reference-guide/models/enrich-your-models#declaring-a-new-field-in-a-model
  const Users = sequelize.define('users', {
    email: {
      type: DataTypes.STRING,
      allowNull: false,
    },
  }, {
    tableName: 'users',
    timestamps: false,
  });

  // This section contains the relationships for this model. See: https://docs.forestadmin.com/documentation/v/v6/reference-guide/relationships#adding-relationships.
  Users.associate = (models) => {
    Users.hasMany(models.posts, {
      foreignKey: {
        name: 'userIdKey',
        field: 'user_id',
      },
      as: 'posts',
    });
    Users.hasMany(models.comments, {
      foreignKey: {
        name: 'userIdKey',
        field: 'user_id',
      },
      as: 'comments',
    });
  };

  return Users;
};

3. Finally, we use the so call “connection” with the models inside
app.js

const forest = require("forest-express-sequelize");
// Retrieve connections build inside models/index.js
const { connections } = require('./models/');

...
Your code
...

// Define forest
forest.init({
  envSecret: process.env.FOREST_ENV_SECRET,
  authSecret: process.env.FOREST_AUTH_SECRET,
  objectMapping: Sequelize,
  connections,
}).then((FAMiddleware) => {
  app.use(FAMiddleware);

  app.listen(port, () => {
    console.log(`Example app listening at http://localhost:${port}`)
  })
})

Tell me if it helps to understand how this work ?

Kind regards,
Morgan

1 Like

Hi @morganperre,

thank you for you post. Unfortunately, I am new in sequelize and so it took me a couple of hours to figure out, that you simply use sequelize-cli that build that file structure for you. However, that is not the only way how to work with sequelize but probably the only way how to apply forest admin on sequelize.

You can recommend this video, that help me :slight_smile:

So, I made some progress and forest admin somehow sees my models, but I am getting warning right now, that I am unable to authenticate. It seems like something should run on localhost:3310?

Thank you for your help,

Vaclav

Just one more thing, these are my headers:

app.use((req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", "https://app.forestadmin.com");
  res.setHeader(
    "Access-Control-Allow-Methods",
    "GET, POST, OPTIONS, PUT, PATCH, DELETE"
  );
  next();
});

Thank you

Hi @morganperre,

so finally, I was able connect to forest admin! :slight_smile:

Morgan, I am pretty sure that you are trying to do your best, but your installation wizard is really confusing and this could discourage lot of people.

Let me explain you why.

  1. When you are trying to create a new project, you are asked to create a name:
    image

  2. Then you define your source:

  3. Then you choose e.g. http://localhost:3000

  4. Then you should create your admin backend

Everyone would assume, it must work right now, which is absolutely misleading. Nowhere is described that you also need to install forest backend that is accessible on the port 3310. This all is served by your great forest-cli, that creates server.js and necessary middlewares. It will never work without that, but it is not described anywhere.

As already mentioned in my previous post, you also require a specific modules structure that is provided by sequelize-cli, this can be also prepared by your forest-cli. That is such a pity you do not mention that anywhere in the installation wizard.
Nothing is even written about that in your documentation:

If you follow step-by-step this tutorial from scratch, you won’t definitely install forest admin, because the whole server part on port 3310 is missing.

I hope it does not sound just as critic, I just wanted to help you to stop loosing your customers.

Best regards,

Vaclav

1 Like

Hi,
I guess I found the issue. In the step where people are allowed to choose the port, e.g. http://localhost:3000, it seems that only 3310 works anyway and your server is trying to approach this endpoint.

Best regards,

Vaclav

1 Like

Hello @Vaclav,

Sorry that you encounter some issue during the onboarding. We try to provide the smoothest experience for our users. So any constructed critics are welcomed !

I’ll try to be as clear as possible. There is 2 main way to integrate Forest Admin either by choosing a data source (eg. Postgress, MySQL, MongoDB …) or what we call InApp (eg. Express/Sequelize, Express/Mongoose).

  • When choosing a data sources, the necessary files (also the sequelize one) are automatically generated.
  • When choosing the InApp you’re the one in charge to generate those files since you are integrating Forest Admin into an existing application. (but clearly we need to have a more mature documentation)

As you said, I’m sure we can still improve the experience by smoothing those first steps.

I’ll forward your feedback right now to our team !

That’s not the intended behaviour ! I’ll try to reproduce on my side !

Thanks for all your feedbacks, it’s appreciable.

Kind regards,
Morgan

Hey again,

I tried to reproduce the issue, but I’m not able to reproduce it.

I’m wondering, how you ended up with the wrong endpoint. Can you share your project name ?

Also, why did you choose the Express / Sequelize datasource ? (It’s important that we understand your need on this one and if the onboarding mislead you to choose this one against another simpler solution → project generated with the forest-cli when using postgres as a datasource)

Thanks again for your help.

Kind regards,
Morgan

Hello Morgan,

I can imagine how hard it is to keep documentation updated together with continuously evolving forest admin itself and synchronise that all together.

To your questions.

I already deleted that project, but you can see it in this screenshot (this is the screenshot from that previous case).

Now, I tried to reproduce that and I am getting a slightly different errors:

As you see, there is this congratulation page, but I can’t go further or click on anything.

  • Project is called: qms-test

When I just leave this page, go to my administration and enter the project again, everything is running properly already. But now, the server port does not make any difference. It works on both 3000 and 3310.

Thank you,
Vaclav

Hi Morgan,

to your second question why I decided for Express / Sequelize. I didn’t know that project based on sequelize using forest-cli will be created. And so I created Sequelize project on my own and then choosed this option.

Best regards,
Vaclav

Hi Morgan,

regarding this picture:

Sorry, my mistake, I didn’t realise I need to vote first :slight_smile:
Otherwise, it would work.

Unfortunately, I can’t reproduce that mistake, but now it works already. No matter, if I chose 3000 or 3310 port. So, maybe, I messed something up.

Nevertheless, I created my project from scratch as your proposed. Just created database and then used the choice “postgress” and not “express/sequelize”.

I worked fine and was pretty easy, indeed.

Thank you for your help,

Vaclav

1 Like

Hello @Vaclav,

Glad to hear that !

We are still trying to improve our flow to provide proper documentation.

Again, thanks for all your feedbacks !

Kind regards,
Morgan