Home > Enterprise >  GET Method failing on Node.js Express backend application
GET Method failing on Node.js Express backend application

Time:05-03

I am trying to create a backend application using Node.js and Express to get post and modify user data from a .json file. Here is my app.js file:

const express = require("express");
const fs = require("fs");

//setting up the express router
const app = express();

app.use(express.json());

//write the code for routes here
app.post("/add", function(req, resp){

 var jsonObject = req.body;
 var jsonFile = fs.readFileSync("get.json", "UTF8");
 var jsonArray = JSON.parse(jsonFile);
 jsonArray.push(jsonObject);

 jsonFile = JSON.stringify(jsonArray);
 resp.json(jsonFile);
 fs.writeFileSync("get.json",jsonFile,"utf-8");

});
app.get('/view/:id?', function(req, resp){
  var queryURL = url.parse(req.url, true).query;
  var jsonFile = fs.readFileSync("get.json", "UTF8");
  var data = JSON.parse(jsonFile);
  var id = req.params.id;
  // if(typeof queryURL.id === "undefined" || queryURL.id == 0){
  //   resp.json(data);
  // }else{
  //   resp.json(data[queryURL.id-1]);
  // }
  if (id >= 0) {
    data.array.every(user => {
        if (user.id === id) {  
            resp.json(user);
            return false;
        } else {
            console.log("Next")
        }
    });
  } else{
    resp.json(data);
  }

});

app.patch("/edit/:id", function(req, res){
    let userID = req.params.id;
    let userFile = fs.readFileSync("get.json", "UTF-8");
    let userArray = JSON.parse(userFile);
    
    let reqUserObject = req.body;

    let newUserArray = userArray.map(user => {
        if (user.id === userID) {
            updatedUser = {...user, ...reqUserObject};
            return updatedUser;
        } else {
            return user;
        }
    });
    
    userFileData = JSON.stringify(newUserArray);
    res.json(userFileData);
    fs.writeFileSync("get.json", userFileData, "UTF-8");
});
module.exports = app;

All methods work except for

app.get('/view/:id?', function(req, resp)

This Method has an optional query parameter id, if you pass an id you get a user with an id equal to that id. If you dont pass in an id, you get all the users from get.json.

The json file (get.json) I used is:

[{"id":"1","name":"updated name","age":"22","gender":"Male","email":"[email protected]"},{"id":"2","name":"user two","age":"24","gender":"Female","email":"[email protected]"},{"id":"3","name":"user three","age":"23","gender":"Male","email":"[email protected]"},{"id":"4","name":"user four","age":"21","gender":"Male","email":"[email protected]"}]

And my test file is:

const request = require("supertest");
const app = require("../app");
const md5 = require("md5");
const fs = require("fs");

//updating a user profile
test("Updating a user", async () => {
  await request(app)
    .patch("/edit/1")
    .send({
      name: "updated name",
    })
    .expect(200);
  setTimeout(() => {
    const data = JSON.parse(fs.readFileSync("../post.json"));
    expect(data.length).toBe(5);
    expect(data[0].name).toBe("updated name");
  }, 1000);
});

// // posting a data
test("Posting a new data", async () => {
  await request(app)
    .post("/add")
    .send({
      id: "5",
      name: "user new",
      age: "36",
      gender: "Female",
      email: "[email protected]",
    })
    .expect(200);
  setTimeout(() => {
    const data = JSON.parse(fs.readFileSync("../post.json"));
    expect(data.length).toBe(5);
  }, 1000);
});

//checking the get route
test("Getting all the user data", async () => {
  const response = await request(app).get("/view").expect(200);
  expect(response.body.length).toBe(4);
  expect(md5(response.body)).toBe("f1d3ff8443297732862df21dc4e57262");
});

//getting profile of a user based on id
test("Getting a single user data", async () => {
  const response = await request(app).get("/view?id=2").expect(200);
  expect(response.body.length).toBe(1);
  expect(md5(response.body)).toBe("93b885adfe0da089cdf634904fd59f71");
});

When I run the tests I get:

rm -rf ./test-report.xml && CI=true ./node_modules/.bin/jest --testResultsProcessor ./node_modules/jest-junit-reporter --forceExit; t-reporter --forceExit;.bin/jest --testResultsProcessor ./node_modules/jest-juni FAIL test/app.test.js ✓ Updating a user (45ms) ✓ Posting a new data (17ms) ✕ Getting all the user data (10ms) ✕ Getting a single user data (4ms)

● Getting all the user data

expected 200 "OK", got 500 "Internal Server Error"

  39 | //checking the get route
  40 | test("Getting all the user data", async () => {
> 41 |   const response = await request(app).get("/view").expect(200);
     |                                                    ^
  42 |   expect(response.body.length).toBe(4);
  43 |   expect(md5(response.body)).toBe("f1d3ff8443297732862df21dc4e57262");
  44 | });

  at Object.<anonymous>.test (test/app.test.js:41:52)
  ----
  at Test._assertStatus (node_modules/supertest/lib/test.js:252:14)
  at node_modules/supertest/lib/test.js:306:17
  at Test._assertFunction (node_modules/supertest/lib/test.js:285:13)
  at Test.assert (node_modules/supertest/lib/test.js:164:23)
  at Server.localAssert (node_modules/supertest/lib/test.js:120:14)

● Getting a single user data

expected 200 "OK", got 500 "Internal Server Error"

  46 | //getting profile of a user based on id
  47 | test("Getting a single user data", async () => {
> 48 |   const response = await request(app).get("/view?id=2").expect(200);
     |                                                         ^
  49 |   expect(response.body.length).toBe(1);
  50 |   expect(md5(response.body)).toBe("93b885adfe0da089cdf634904fd59f71");
  51 | });

  at Object.<anonymous>.test (test/app.test.js:48:57)
  ----
  at Test._assertStatus (node_modules/supertest/lib/test.js:252:14)
  at node_modules/supertest/lib/test.js:306:17
  at Test._assertFunction (node_modules/supertest/lib/test.js:285:13)
  at Test.assert (node_modules/supertest/lib/test.js:164:23)
  at Server.localAssert (node_modules/supertest/lib/test.js:120:14)

Test Suites: 1 failed, 1 total Tests: 2 failed, 2 passed, 4 total Snapshots: 0 total Time: 1.612s Ran all test suites. Force exiting Jest: Have you considered using --detectOpenHandles to detect async operations that kept running after all tests finished?

We can see the last 2 tests ("Getting all the user data" and "Getting a single user data") did not pass. These 2 test the app.get('/view/:id?', function(req, resp) method.

How could I fix my app.get('/view/:id?', function(req, resp) method?

Update:

I fixed my app.js according to the suggestion of Yago Biermann, but it is still unable to pass the last 2 tests. My revised app.js:

const express = require("express");
const fs = require("fs");

//setting up the express router
const app = express();

app.use(express.json());

//write the code for routes here
app.post("/add", function(req, resp){

 var jsonObject = req.body;
 var jsonFile = fs.readFileSync("get.json", "UTF8");
 var jsonArray = JSON.parse(jsonFile);
 jsonArray.push(jsonObject);

 jsonFile = JSON.stringify(jsonArray);
 resp.json(jsonFile);
 fs.writeFileSync("get.json",jsonFile,"utf-8");

});
app.get('/view', function(req, resp) {
  
  const id = req.query.id;
  var jsonFile = fs.readFileSync("get.json", "UTF8");
  var data = JSON.parse(jsonFile);
  // return the whole data if query parameter wasn't provided
  if (!id) return resp.status(200).json(data)

  // you should use find instead of every to get the user data
  const user = data.find(user => {
    if (user.id === id) {
      return user;
    };
      return null;
  });
  // return the user otherwise return a 404 response
  return user ? resp.status(200).json(user) : resp.status(404).json({message:"user not found"})
});

app.patch("/edit/:id", function(req, res){
    let userID = req.params.id;
    let userFile = fs.readFileSync("get.json", "UTF-8");
    let userArray = JSON.parse(userFile);
    
    let reqUserObject = req.body;

    let newUserArray = userArray.map(user => {
        if (user.id === userID) {
            updatedUser = {...user, ...reqUserObject};
            return updatedUser;
        } else {
            return user;
        }
    });
    
    userFileData = JSON.stringify(newUserArray);
    res.json(userFileData);
    fs.writeFileSync("get.json", userFileData, "UTF-8");
});
module.exports = app;

And what I get when I run the tests:

rter --forceExit;es/.bin/jest --testResultsProcessor ./node_modules/jest-junit-repo FAIL test/app.test.js ✓ Updating a user (43ms) ✓ Posting a new data (15ms) ✕ Getting all the user data (9ms) ✕ Getting a single user data (4ms)

● Getting all the user data

expect(received).toBe(expected) // Object.is equality

Expected: 4
Received: 5

  40 | test("Getting all the user data", async () => {
  41 |   const response = await request(app).get("/view").expect(200);
> 42 |   expect(response.body.length).toBe(4);
     |                                ^
  43 |   expect(md5(response.body)).toBe("f1d3ff8443297732862df21dc4e57262");
  44 | });
  45 |

  at Object.<anonymous>.test (test/app.test.js:42:32)

● Getting a single user data

expect(received).toBe(expected) // Object.is equality

Expected: 1
Received: undefined

  47 | test("Getting a single user data", async () => {
  48 |   const response = await request(app).get("/view?id=2").expect(200);
> 49 |   expect(response.body.length).toBe(1);
     |                                ^
  50 |   expect(md5(response.body)).toBe("93b885adfe0da089cdf634904fd59f71");
  51 | });
  52 |

  at Object.<anonymous>.test (test/app.test.js:49:32)

Test Suites: 1 failed, 1 total Tests: 2 failed, 2 passed, 4 total Snapshots: 0 total Time: 1.71s Ran all test suites. Force exiting Jest: Have you considered using --detectOpenHandles to detect async operations that kept running after all tests finished?

CodePudding user response:

The problem seems to be at your tests, in your test "Getting all the user data" you are making a request to /view but you don't have any route to view, at least it's not in your question, note that /view/:id is not the same as /view. Lastly, in your test "Getting a single user data" you are not providing the id for the user as a url parameter, instead you are passing it as a query parameter, so try to do the following:

test("Getting a single user data", async () => {
  // pass the id as url
  const response = await request(app).get("/view/2").expect(200);
  expect(response.params.id).toBe(2);
  expect(response.body.length).toBe(1);
  expect(md5(response.body)).toBe("93b885adfe0da089cdf634904fd59f71");
});

See the docs about req.params. Hope I helped a bit!

Edit: As you said that the test file can't be changed, do the following in your view route:

// Change to view, now the test on route /view should work
app.get('/view', function(req, resp) {
  
  const id = req.query.id;
  var jsonFile = fs.readFileSync("get.json", "UTF8");
  var data = JSON.parse(jsonFile);
  // return the whole data if query parameter wasn't provided
  if (!id) return resp.status(200).json(data)

  // you should use find instead of every to get the user data
  const user = data.find(user => {
    if (user.id === id) {
      return user;
    };
      return null;
  });
  // return the user otherwise return a 404 response
  return user ? resp.status(200).json([user]) : resp.status(404).json({message:"user not found"})
});
  • Related