loading...

Help with a beginner's project! An app with Front and Back-end.

lucasmrl profile image Lucas L. ・1 min read

Night DEV community!

This is a beginner's question and I'm really looking forward to learning from you now. 😄

Context:
I want to create a project to put in practice some skills that I just learned.
The idea: An APP with authentication and different views according to the user's role.

  • Frot-end: React-native OR Flutter.
  • Back-end: Express.js(Node.js) AND MongoDB.

Features:

  • Users should be able to create an account/ sign in and sign out.
  • There will be 2 types of users: NORMAL USER and STORE.
  • Normal User = One e-mail and one password. Impossible to have two of the same. It will have access to some features on the app (CRUD operations).
  • STORE = This user will have one e-mail and one password.It will have access to some features on the app (CRUD operations). The CATCH: this user will be able to create sub-users with the same access to the same features as the main STORE USER.

Questions:

  1. I know how to authenticate using Express (JWT, Passport, Middlewares, etc). Is that a common/best practice for an app? Use the authentication on the endpoints/requests?
  2. The relationship between a STORE user and it's sub-users would be one-to-few. So, should I have them referenced inside my schema or actually embed them inside the STORE schema?

Not sure if I was clear but I hope to get some insight before starting coding and figure out that I went the wrong way. 😌🤓

Thank you!

Posted on by:

lucasmrl profile

Lucas L.

@lucasmrl

Born and raised in Brazil. Focusing on Javascript! 😃

Discussion

markdown guide
 

Hi, Lucas!
I'm not telling about best practices, but from my experience:

  • Yes, you can use JWT + Passport.js for the purpose you described. Passport gives you the simplicity of integrating many authentication schemes such as raw email + password, Twitter, Google, etc. You can also use just JSON web tokens, it will be simpler as you don't necessarily need Passport.js. Say, you have "/sign-up" endpoint where you create a JWT token and write required payload (in your case it is at least a role of a user) and send it back to a client and "/sign-in" where you authenticate a user. When a client makes a request to your backend, you can parse[1] a JWT token to extract a user's role and define the next logic.

[1] For this purpose you can have a middleware, which can be used in protected endpoints, that extract a JWT token from a request (e.g. a client sends a token in the request body), decodes it and receives a user's role (and other payloads if you put it there) and you can put the extracted payload to, say, "req.user", so it will be available in your next functions (endpoints handlers - controllers):

handleProtectedEndpoint (req, res) {
 const role = req.user.role;
 if (role === 'STORE') {
  // ... 
 }
 return res.sendStatus(200);
}

"The relationship between a STORE user and it's sub-users would be one-to-few. So, should I have them referenced inside my schema or actually embed them inside the STORE schema?"

You could embed other documents (users as you say) to a user document, like this:

// define a User model, pseudocode
const user = mongodb.Schema({
 email: { type: String, required: true, unique: true },
 role: { type: String, required: true },
 password: { type: String },

 // you'll put sub-users here
 users: { type: Object },
})

But this method has cons:

  • "users" field uses a document space not in a good way: takes additional space + duplicating users.
  • what if you need to know if a particular user is belonging to a store? You will need to fetch all the stores and parse their users to find out.
  • in case of updating "user" schema - e.g. adding/removing/changing existed fields, say, you rename "email" field to "emailAddress" and add a field "name" with default value - in this case, "users" you put in stores will be outdated and you need to make additional checks on documents fetching or to make a manual migration.

So, it is better to make a reference, like this:

// define a User model, pseudocode
const user = mongodb.Schema({
 // ... user's fields

 // so, "users" is an array of User references
 users: [{ type: mongodb.ObjectId, ref: 'User' }],
})

And in case you need to find out what users belong to a store, your query will be:

// mongoose pseudocode
const users = await User.findOne({ email: storeEmail }).populate('users');
// "populate" will fetch users documents by references
 

Wow Sergiy, thank you for your detailed response. I am glad that I actually fully understand both.😁. I didn't think about the cons in embedding before posting. It makes sense to me the pros in referencing. Thanks again!

 
  1. Passport sounds nice, but you haven't said what authentication types you're trying to support.

  2. Sounds like you're wondering where you should store the data. Grease the wheels by making it easy to access, then shard when you know it'll scale better otherwise. KISS, until you're app complains while keeping an eye out for security concerns.

 

Hey Bramer!

  1. Yes, my mistake. It would be the traditional email and in the future I would have Google and Facebook accounts.
  2. I always forget about KISS when I want to start something 😅. You are right. One thing at a time.

Thank you for your great help!