0

I'm creating a JS web app using NodeJS and Express (with SQL/MySQL for the database), pretty much directly implementing this API tutorial: https://www.bezkoder.com/node-js-rest-api-express-mysql/ (just replacing 'tutorials' with 'Employees').

I'm trying to write API functions to get all Employees with certain attributes (in the SQL table), for example all employees with lastName = "Garcia" or all employees with teamID = 43682, etc.

In my routes.js file I have this:

module.exports = app => {
  const employees = require("../controllers/employee.controller.js");

  const router = require("express").Router();

  // Create a new Employee
  router.post("/", employees.create);

  // Retrieve all Employees
  router.get("/", employees.findAll);

  // Retrieve all Employees with lastName
  router.get('/', employees.findLastName);


... a bunch more CRUD functions ...


  app.use('/api/employees', router);
};

And this is the corresponding Controller function:

exports.findLastName = (req, res) => {
  const lastName = req.query.lastName;   // tried changing req.query.lastName to req.params.lastName

  Employee.getLastName(lastName, (err, data) => {
    if (err)
      res.status(500).send({
        message:
            err.message || "Error occurred while retrieving by last name."
      });
    else {
      console.log(`Employees with lastName ${lastName} were found!` );
      res.send(data);
    }
  });
};

exports.findAll = (req, res) => {
  const title = req.query.title;

  Employee.getAll(title, (err, data) => {
    if (err)
      res.status(500).send({
        message:
          err.message || "Some error occurred while retrieving employees."
      });
    else {
      console.log(`Employee with ${title} title was found!` );
      res.send(data);
    }
  });
};

The findAll route/function (just copied from that tutorial) works by finding all Employees with a certain ID number (the primary key in the DB) and I know that works from testing it through Postman. I wrote the findLastName route/function by copying the findAll function and changing it to search by lastName, and making the corresponding functions in the model and controller classes.

The new function, findLastName, doesn't work... unless I put the route before the findAll route (or comment it out). Then it correctly calls all my functions and returns all employees with the lastName param.

What's actually happening here? Are you not allowed to have multiple .get() routes or something? If so, how would I implement a search API like this? This is my first time building a web app like this so admittedly I'm still a little hazy on how routing and all that works. Thank you for any help though!

  • You can have multiple `.get` routes, but they must use different paths, for example `router.get('/findAll', ...)` and `router.get('/findLastName', ...)`. How else shall the server decide what the client wants? – Heiko Theißen Nov 08 '22 at 17:09
  • @HeikoTheißen This totally makes sense! Sorry I'm still hazy on paths and routing though, where would I actually define those custom paths? I tried adding those to my router as is but it didn't work, I'm guessing I have to define an actual .../findAll path for example? – TorusWithSprinkles Nov 08 '22 at 17:17

1 Answers1

1

In Express whenever the first route matches second will be ignored, so in your scenario you have two route.get with same path /

router.get('/', employees.findAll);

//Since route with path `/` is matched above already this will be ignored 
router.get('/', properties.findLastName);

In order to find Employees with last name you will need to create a new route with param (param will contain the last name)

router.get('/:lastName', properties.findLastName);

You can access the param value like this req.params.lastName in controller

Shivam
  • 3,514
  • 2
  • 13
  • 27
  • That definitely makes sense, thank you! I'm still having some trouble implementing it. I changed the router to include that param, *edit: I added my controller function to the main post* - It seems to be just ignoring that route/get request and nothing is happening. – TorusWithSprinkles Nov 08 '22 at 17:32
  • @TorusWithSprinkles can you post how your URL look like, when you are sending request? – Shivam Nov 08 '22 at 17:40
  • So the URL I defined in the routes class (I posted the whole thing above) looks like `app.use('/api/employees', router);` and then the get route now looks like this: `router.get('/:lastName', employees.findLastName);` - And finally I'm sending the request in Postman which generates a URL that looks like this: `http://localhost:8080/api/employees?lastName=Garcia` – TorusWithSprinkles Nov 08 '22 at 21:24
  • @TorusWithSprinkles that's wrong you should be sending `lastname` like this `http://localhost:8080/api/employees/Garcia`. What you are doing right now is you are sending `query param` not `path param`. Your `GET` call accepts `Path Parameters` not `Query`. More info [here](https://stackoverflow.com/questions/30967822/when-do-i-use-path-params-vs-query-params-in-a-restful-api) – Shivam Nov 09 '22 at 00:32
  • Okay I think that makes sense... but I'm confused because the findLastName() function *does* work (when I put i before the other .get route as I mentioned), it returns all employees with the desired name and it uses query. The answer in the post you linked seems to be saying that you should use a Query param for this situation too, right? Like they used `/cars?color=blue&brand=ferrari` as an example, which is exactly like what I want to do eventually (return all employees with a certain last name, and maybe team-name or something). Thanks so much for your help btw! – TorusWithSprinkles Nov 09 '22 at 16:39
  • @TorusWithSprinkles If you want to use `query params` that's totally fine, you can keep your URL `http://localhost:8080/api/employees?lastName=Garcia`. If you want to use `query params` you won't be able to use 2 routes. You'll have to modify your `findAll` controller function. You will have to add a condition `if last name in query params exist, search by last name otherwise search all`. You can't have 2 distinct route if you want to use `query params` – Shivam Nov 09 '22 at 18:35
  • Ahh okay I think I'm starting to understand this now haha. So I would need a condition like that in findAll for each Employee property I want to search by? So for instance, a condition for last name, a condition for firstname, etc.? I'm also having a hard time figuring out the condition... would be be something like `if (req.query.contains(req.body.lastname)` ? That's giving me an error but am I sorta on the right track? I cant figure out how to test the lastname against the actual query param. – TorusWithSprinkles Nov 09 '22 at 19:17
  • 1
    @TorusWithSprinkles `req.query` will return you an object like this `{lastName : 'Garcia'}`. You can use [hasOwnProperty](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty) to check if `lastName` exist. Something like `if (req.params.hasOwnProperty('lastName'))` this will return you `true/false` then you can go on from there. – Shivam Nov 09 '22 at 19:31
  • 1
    PS - This question is now getting diverged from what it originally was, so I won't be commenting anymore. If you have more query please open a new question. Upvote and mark as correct. If this helped :) – Shivam Nov 09 '22 at 19:35