1

This is a learning struggle, and I might just be approaching this from an awkward angle, but guidance is appreciated. This project is using just HTML, Node, and Express.

I have a small app that is supposed to take survey inputs to build a 'friend' profile (essentially only a name, imgURL, and 7 question answers each a value 1-5). I want to save all the Friend objects with those properties in a JSON file in a data sub-directory so that as new users are added, I can compare the friend objects against one another.

On my front end, I want to step through each stage one bootstrap card at a time, so I have a questions.js file that manipulates the DOM to start with the name and imgURL and create a new 'Friend' object, then go one question at a time (printing question text from an array of strings) and capturing radio button selections (values 1-5) on("submit"). End result is I have iterated through all the questions, grabbed the submitted values, and pushed them to a 'scores' array within the friend object, resulting thusly:

{
    "name": "Ahmed",
    "photo": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/6/005/064/1bd/3435aa3.jpg",
    "scores": [5, 1, 4, 4, 5, 1, 2, 5, 4, 1]
  }

All of this works nicely, and I end up with good User navigation through the questions and a new Friend object with all my desired data persisting in the linked JS file.

Now how the ding-dang do I push that new Friend object as an array item in my friends.json file? I kind of get that I need maybe an Ajax call within the questions.js, or maybe I'm off-base and this belongs within an app.post route in my server.js, but so far my research and trials have only served up more confusion.

This might be a wack question, but I think there is a best practice in there I need to learn. Any insight is much appreciated!

Kevin H.
  • 318
  • 2
  • 15

1 Answers1

3

Doing a POST request using the Fetch API

As you have mentioned, you need a POST route in your server to handle that.

Your frontend should do an AJAX POST call to that endpoint with that newly created object. You can use the Featch API to do that:

fetch('http://localhost:8080/api/friends', {
    method: "POST",
    headers: {
        "Content-Type": "application/json; charset=utf-8",
    },
    body: JSON.stringify({
        name: "Ahmed",
        photo: "https://media.licdn.com/.../foo.jpg",
        scores: [5, 1, 4, 4, 5, 1, 2, 5, 4, 1],
    }),
});

Modify the data on the backend

Then, assuming this is just a simple learning example, on your backend you have two options:

  • Have that friends.json file already loaded in memory as an array and just push a new element to it.
  • Load, parse and save friends.json on every request.

If this is meant to be a production server, then you might consider using REDIS, MongoDB or any other database that fits your needs.

Here you can see both of them:

// This will be loaded and parsed already (only used in option 1):
const friends = require("../data/friends.json");

// Only used in option 2:
const fs = require('fs');

// Tell the server to parse JSON bodies in your requests:
const bodyParser = require("body-parser");
app.use(bodyParser.json()); // Support JSON-encoded bodies.

// Get existing friends:
app.post('/api/friends', function(req, res, next) {
    // Option 1, persisted in memory:
    res.json(friends);

    // Option 2, loaded and saved everytime:
    try {
        res.json(JSON.parse(fs.readFileSync("../data/friends.json")));
    } catch(err) {
        // JSON.parse might fail:
        next(err);
    }
});

// Create new friend:
app.post('/api/friends', function(req, res, next) {
    // Option 1, persisted in memory:
    friends.push(req.body); // This should be validated properly!
    res.json(friends);

    // Option 2, loaded and saved everytime:
    try {
        const friends = JSON.parse(fs.readFileSync("../data/friends.json"));
        friends.push(req.body); // This should be validated properly!
        fs.writeFileSync("../data/friends.json", JSON.stringify(friends));
        res.json(friends);
    } catch(err) {
        // JSON.parse or fs.writeFileSync might fail:
        next(err);
    }
});

✨ Recommended way to use body-parser

As an additional suggestion, even though you will see body-parser being used as app.use(bodyParser.json()) in a lot of resources out there, the recommended way to use it is to add it only to the route it is relevant for:

Express route-specific

This example demonstrates adding body parsers specifically to the routes that need them. In general, this is the most recommended way to use body-parser with Express.

So, in your case you would do:

const bodyParser = require("body-parser");
const jsonParser = bodyParser.json();

...

app.post('/api/friends', jsonParser, function(req, res, next) { ... }
Danziger
  • 19,628
  • 4
  • 53
  • 83
  • 1
    Thank you for the robust answer! I will work with this and return if I have any questions or issues. Much appreciated. – Kevin H. Nov 06 '18 at 04:45
  • 1
    Have you added `body-parser`? Are you sending the right `Content-Type` header? You can try doing a `POST` with Postman to make sure the problem is not on your frontend. Maybe this other question can help: https://stackoverflow.com/questions/24543847/req-body-empty-on-posts – Danziger Nov 06 '18 at 18:47
  • @KevinHyde You have deleted the previous comment right? I was going crazy thinking I wrote it in the wrong tab – Danziger Nov 06 '18 at 18:48
  • 1
    Yep, I just now saw my issue . . . . middleware from your example was set with `app.use(bodyParser.json());` and my routing file was configured using `var router = express.Router();`. Swapped `app.` for `router.` and I am back in business! Thanks again. – Kevin H. Nov 06 '18 at 18:49