Confusion about structuring node mongodb api

Hello Everyone,
I want to know How to structure an nodejs api.
For example:
I have an api that returns data for laptop, mobile and camera
Should I create a seperate route for each i.e /laptop or /mobile or /camera and then it returns JSON data for each one like this.

[
    {
        "brand": String,
        "price": number
    },
    {
        "brand": String,
        "price": number
    }
]

or I create a one route i.e /devices and it returns data like this

[
    laptops: [
    {
        "brand": String,
        "price": number
    },
    {
        "brand": String,
        "price": number
    }
    ],
    mobiles: [
    {
        "brand": String,
        "price": number
    },
    {
        "brand": String,
        "price": number
    }
    ],
    cameras: [
    {
        "brand": String,
        "price": number
    },
    {
        "brand": String,
        "price": number
    }
    ]
]

I find that making post req to the first method is easy like(/laptop, /cameras)
but I don’t find a way to post the data to a certain type of device in the 2nd method.
Which way should I use to make this API so that I can use it on my react native andriod app?
Please anyone help me .

Based on what your data is, I’m gonna assume your queries are:

  • get all products
  • get all products of a type (laptops/mobiles/cameras)
  • get a product
  • add a product
  • delete a product

So

[
  {
    "brand": String,
    "price": number,
    "productType": String
  }
]

Where productType is laptop/mobile/camera. Then add an index on productType to enable querying against it.

This doesn’t make any difference, what the client is (an Android app in this case) isn’t relevant. It shouldn’t know anything about the data structure in MongoDB, it just asks for products.

So the queries from the client should just [I assume] be what I wrote in the first paragraph. So if you want all laptops (for example), you just ask for all laptops. And the query under the hood is going to search products filtered on productType of “laptop”

If the objects in the Db were drastically different things (so each one has completely different fields), then it makes sense to divide them up, but as things stand it doesn’t – they are all just products.

Hello Dan,
Thanks for your detailed explanation.
If I want to get all laptop then first I have to do get that array of data(items) then I have to do like this.
const laptop = items.filter(item => item.productType = 'laptops');
Now, I should pass down this laptop array as a prop down to the show screen.
Am I right up to this point?
What I want is that when user visit the laptop screen, user can see only one laptop at a time and when user click on the next arrow, then next laptop should visible with its name and image?
Screenshot from 2020-12-29 17-31-16
This is my mongoose schema (as you mentioned in your answer)

[
  {
    "id": String,
    "brand": String,
    "price": number,
    "productType": String,
    "image": String
  }
]

Is this schema works fine for what I want to accomplish?

I have one more doubt: after creating an api I have to host it somewhere(heroku) then I’ll get a link from there so that I can call different endpoints but when I use that link on my app to fetch data. Is it possible for the user to see that link? If user can see that link they can easily able to use somewhere.
Thank You.

Right, this should not happen in-app. You are using a database which is designed to be able to support doing this efficiently. In the app, the query should just ask for laptops and that’s what the dB should return. By just getting everything and filtering on the front end you’re trying to do the dB’s job.

At first, when you only have a few products, it will actually be simpler to get everything then filter on the front end, but this normally isn’t a useful pattern IRL because it’s really inefficient.

Separate what the data access and the UI in your head here. What you’re describing is a list of products of type laptop – you’ve grabbed the array of laptop-type objects and you’re just displaying them one by one.

Thanks for your quick reply.
Please tell me about this

Now, I am querying the data like this
http://localhost:3000/items?q=laptop
is the letter q can be anything i.e. query?
and then getting the data like this.

router.get('/items', async (req, res) => {
    console.log(req.query.q);
    const items = await Item.find({ productType: 'laptop'});
    res.send(items);
});

Do I need to add anything other than this in my code to query the data?
One more thing I want to know is that Should I query the data using .findOne({ productType: 'laptop'}) or .find({ productType: 'laptop'})?
Is second method work fine in my case? I want to show only one laptop at a time.

Yes, if you just make that application (the one serving the API routes) public then yes, if they so wished they could just use the endpoints directly. There are many good guides to setting up a Node API in Heroku in the Heroku documentation and via Google, so I won’t go into how. There are ways to lock it down if you want to make sure users can only access it via your app, but again, there are a lot of guides to this which explain things better than I can, so do have a Google.

I can’t really answer this, as it depends on what you want to show to the user. A normal pattern is to grab a collection of items (so, laptops), and then loop through them in the app. This is normally a bit more efficient – if you think about a product site, you get a list of products when you look for something, then you can select one of them to get more details. In your case, it seems to makes sense from an efficiency point of view to get that collection rather than one, then another one, then another one etc. If you load in a lot of them, then it’s a little bit slower at first but then much much faster in-app because you already have those data (so find rather than findOne). But as I say, it’s completely dependent on what is best in your specific case.

Yeah, it’s just whatever makes sense – it’s just the name of a query string key, so it can be anything.

Hello Dan,
Happy New Year
I tried to find resources related to how to lock down api so only user can use it through my app but I can’t able to find any. I don’t want user to find my hosted api url and use it somewhere else.So, How to hide api url from the user so, user can use that api only through my app.
Please help me with this
I deployed to heroku successfully.
Thanks

Google authentication for Node REST APIs. The issue you have is that if the two things are in different places, the user of the client app will need to authenticate every time they use it, because they will then need to be authenticated by the API app (so for example they will need to have some kind of password login to use the app). Essentially, to access the API, the API will need some kind of authorization token sent by the client that says “I am the client app”. You can’t hardcode that into the app, because that is nearly the same as not having any authentication (JS code is visible to anyone using that client app, so anyone who wants to can just copy the code and access the API). So you need some step that generates a valid auth token, which is the login step. Note this is how basically all mobile apps do it (you often don’t notice though, because the login step is when you first open the app, then the token is stored so it authenticates automatically after that).

You could keep the API public, that makes things much easier and is more sensible, then you need login only when a user does something that isn’t just browsing a catalogue of products. This is normal for the vast majority of e-commerce websites.

Note you can use the Node app to serve the client app, so it’s all the same application – there wouldn’t be a seperate API. This is simpler than separating the two things. If the client app is the only thing that accesses the API, think very carefully about what you gain by separating them – afaics, not much. Distributed systems are hard , and in the case of having a seperate client and API server app, thats a [simple] distributed system. You have two apps, and although each on its own is simpler than just having one app, you now have to deal with the multifarious issues involved in getting them to talk to each other. Authorisation over a network is one of those issues.

Thanks
I think I have to add auth now.