0

i'm facing a problem using fs in a next.js / react app context so i'm doing a little app for renting appartments i have a json file named database.json with some datas in it and i'm able to retrieve it and use it with the Next.js Api routing where i can make my own little API. but when i try to write this file just nothing happened.

stack : React 18 / Next.js 13 / Node 18.0 via npm run dev

Here is my API File

import type { NextApiHandler } from 'next'
import apartmentList from '@/database.json'

import { actions } from '@/helpers/apiAction.js'

var fs = require('fs')

const DeleteApartmentsHandler: NextApiHandler = async (request, response) => {
    const { deleteId } = request.query
    const newDataSet = apartmentList.data.filter((item) => item.id !== Number(deleteId))

    
    if (newDataSet.length === apartmentList.data.length - 1) {
        const makeDelete = actions.delete(Number(deleteId))
        
        if (makeDelete) {
            response.status(200).json(`l'appartement ${deleteId} a bien été supprimé`)
        } else {
            response.status(501).json("Nous avons rencontré un soucis durant la suppression")
        }
    } else {
        response.status(500).json("il semblerait qu'aucun element n'ait été supprimé")
    }
}

export default DeleteApartmentsHandler

This is how i call it (this is not the final version, just working on modifying the file):

fetch(`api/delete/${id}`)
  .then(res => {
    console.log(res)
    // push('/')
  })
  .catch(err => console.log(err))

then this is my helpers/apiActions.js file with the purpose to make the operations on the JSON file

// tried an ES6 import 
// import fs from 'fs'

var fs = require('fs')
let apartmentList = require("../database.json")
// i tried a out of src/ file 
// let apartmentListsec = require("../../database.json")

export const actions = {
    delete: _delete
}

function _delete(id) { 
    const newDataSet = apartmentList.data.filter((item) => item.id !== id)
    
    try {
        fs.writeFileSync("../database.json", JSON.stringify(newDataSet, null, 4))
        return true
    } catch(err) {
        console.log(err)
        return false
    }
}

and finally this is my data : https://file.io/pO2hVHzgIur2

i went on internet and everything, i changed the rights of my files src/, the file that make the update, the api files, etc (i won't make it online) i tried using writeFile (with async) and writeFileSync, i tried to move my files out of src/, i tried to change the TS file to JS

but none of these solutions worked.

i've tried to log my data this formatted how i want without the item i want to remove, the fs.writefilesync function that return 'undefined' i tried to use it from the api file directly or to passe via the helpers/apiActions.js, none work

so Stackoverflow is my last chance, i've spent hours on the problem i can't find what happening wrong

robin
  • 1
  • 1
  • Does this answer your question? [node.js require() cache - possible to invalidate?](https://stackoverflow.com/questions/9210542/node-js-require-cache-possible-to-invalidate) – AKX Mar 22 '23 at 10:30
  • IOW, you can't use `require("...json")` and `fs.write...` to the same JSON file. Use `fs.readFile` and `JSON.parse()` to read the file, not `require`. – AKX Mar 22 '23 at 10:31

1 Answers1

0

To make my comment an answer:

Instead of doing

import apartmentList from '@/database.json'

or

let apartmentList = require("../../database.json")

you will need to use something like

function readApartmentList() {
  // TODO: this should be async!
  return JSON.parse(fs.readFileSync("something/database.json", "UTF-8"));
}

to ensure that the file is always read from the disk, and not cached by the require/import machinery (or worse yet, bundled with your frontend code).

Of course this could be made smarter, e.g. by reading the file only once, and saving it when needed:

let _apartmentList = null;  // This may not be touched by other than these two functions.

function getApartmentList() {
  if(!_apartmentList) {  // Haven't loaded yet.
    _apartmentList = JSON.parse(fs.readFileSync("something/database.json", "UTF-8"));
  }
  return _apartmentList;
}

function saveApartmentList(newData) {
  _apartmentList = newData;
  fs.writeFileSync("something/database.json", JSON.stringify(_apartmentList), "UTF-8");
}

(In anything more than a toy app, this is fraught with race conditions and so on, but it could get you started.)

AKX
  • 152,115
  • 15
  • 115
  • 172
  • i try this right now, thanks for this complete and useful answer :) – robin Mar 22 '23 at 10:58
  • if this is synchrone why couldn't we do : `let _apartmentList = JSON.parse(fs.readFileSync("../database.json", "UTF-8"))` – robin Mar 22 '23 at 11:07
  • Because there's no good reason to read the data into memory before you need to read it the first time. – AKX Mar 22 '23 at 11:11
  • I can actually read the content of the file but i wass triggered when i figured out that i can only retrieve 5 of my items (there is 6 of them) and when i modify my file manually no modification appears, it seems there should be a cache or something, even when i restart the server – robin Mar 22 '23 at 12:19
  • When you modify your file manually while the application is running, changes won't be picked up. The assumption here was that your application is the only thing reading or writing that file. If that's not the case, just remove the `if(!_apartmentList)` stuff so the file is always read from disk. – AKX Mar 22 '23 at 12:56