Struggling with Node.js
Published: 2024-07-06 15:34:59

I am trying to get my first Node.js server to work with React Front-end for a site I am building for a client. I have mostly dealt with Django REST when I need a server but I heard Node.js was simpler and maybe more appropriate for this cause, I am also more comfortable with Javascript.

**Basic structure of the website:**

1. - Form for uploading large amounts of PDF documents, images, power point presentations.
2. - Search functionality for the database to find certain PDFs by author, country, upload date and other values.
3. - I am using React DocViewer to display the PDF documents.

**The Problem:**

The problem I am having now is that I am able to retrive all the saved data as JSON but not display PDF from a single column based on FileId with DocViewer in ViewPdf.js.
.
This is the page for the DocViewer:

```
import React, { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import DocViewer, { PDFRenderer, HTMLRenderer } from "react-doc-viewer";


const ViewPdf = () => {
    const { fileId } = useParams();
    const [fileUrl, setFileUrl] = useState('')

  useEffect(() => {
    // Construct the URL to fetch the file
    const url = `/api/uploads/:fileId`;

    setFileUrl(url);
  }, [fileUrl, fileId]);

  const docs = [
    { uri: fileUrl }
  ];

  return (
    
      <DocViewer 
      pluginRenderers={[PDFRenderer, HTMLRenderer]}
      documents={docs}
      config={{
        header: {
            retainURLParams: true,

            },   
       } } />

    );
}



export default ViewPdf;
```
**The ViewPdf is opened with this Search page:**

```
import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import '@cds/core/select/register.js';

function Search() {
  const navigate = useNavigate();
  const [uploads, setUploads] = useState([]);
  const [filter, setFilter] = useState({
    category: '',
    uploadDate: '',
    author: '',
    country: ''
  });


  useEffect(() => {
    fetch('http://localhost:8000/api/uploads')
      .then(response => response.json())
      .then(data => setUploads(data))
      .catch(error => console.error('Error:', error));
  }, []);

  const handleFilterChange = (event) => {
    const { name, value } = event.target;
    setFilter(prevFilter => ({
      ...prevFilter,
      [name]: value
    }));
  };

  const filteredUploads = uploads.filter(upload => {
    const { category, uploadDate, author, country } = filter;
    return (
      (category === '' || upload.category === category) &&
      (uploadDate === '' || upload.uploaddate === uploadDate) &&
      (author === '' || upload.author === author) &&
      (country === '' || upload.country === country)
    );
  });

  const handleFileClick = (upload) => {
    const fileId = upload.id;
    navigate(`/api/uploads/${fileId}`);
  };

  return (
    <div style={{ display: "flex", justifyContent: "center" }}>
      <div style={{ textAlign: "left" }}>
        <div style={{ marginBottom: "10px" }}>
          <label style={{ display: "inline-block", width: "100px" }}>Category:</label>
          <input type="text" name="category" value={filter.category} onChange={handleFilterChange} />
        </div>
        <div style={{ marginBottom: "10px" }}>
          <label style={{ display: "inline-block", width: "100px" }}>Upload Date:</label>
          <input type="date" name="uploadDate" value={filter.uploadDate} onChange={handleFilterChange} />
        </div>
        <div style={{ marginBottom: "10px" }}>
          <label style={{ display: "inline-block", width: "100px" }}>Author:</label>
          <input type="text" name="author" value={filter.author} onChange={handleFilterChange} />
        </div>
        <div style={{ marginBottom: "10px" }}>
          <label style={{ display: "inline-block", width: "100px" }}>Country:</label>
          <select name="country" value={filter.country} onChange={handleFilterChange}>
            <option value="">All</option>
            <option value="USA">USA</option>
            <option value="Canada">Canada</option>
            <option value="UK">UK</option>
            <option value="Albania">Albania</option>
            <option value="Andorra">Andorra</option>
            <option value="Austria">Austria</option>
            <option value="Belarus">Belarus</option>
            <option value="Belgium">Belgium</option>
            <option value="Bosnia and Herzegovina">Bosnia and Herzegovina</option>
            <option value="Bulgaria">Bulgaria</option>
            <option value="Croatia">Croatia</option>
            <option value="Cyprus">Cyprus</option>
            <option value="Czech Republic">Czech Republic</option>
            <option value="Denmark">Denmark</option>
            <option value="Estonia">Estonia</option>
            <option value="Finland">Finland</option>
            <option value="France">France</option>
            <option value="Germany">Germany</option>
            <option value="Greece">Greece</option>
            <option value="Hungary">Hungary</option>
            <option value="Iceland">Iceland</option>
            <option value="Ireland">Ireland</option>
            <option value="Italy">Italy</option>
            <option value="Kosovo">Kosovo</option>
            <option value="Latvia">Latvia</option>
            <option value="Liechtenstein">Liechtenstein</option>
            <option value="Lithuania">Lithuania</option>
            <option value="Luxembourg">Luxembourg</option>
            <option value="Malta">Malta</option>
            <option value="Moldova">Moldova</option>
            <option value="Monaco">Monaco</option>
            <option value="Montenegro">Montenegro</option>
            <option value="Netherlands">Netherlands</option>
            <option value="North Macedonia (formerly Macedonia)">North Macedonia (formerly Macedonia)</option>
            <option value="Norway">Norway</option>
            <option value="Poland">Poland</option>
            <option value="Portugal">Portugal</option>
            <option value="Romania">Romania</option>
            <option value="Russia">Russia</option>
            <option value="San Marino">San Marino</option>
            <option value="Serbia">Serbia</option>
            <option value="Slovakia">Slovakia</option>
            <option value="Slovenia">Slovenia</option>
            <option value="Spain">Spain</option>
            <option value="Sweden">Sweden</option>
            <option value="Switzerland">Switzerland</option>
            <option value="Ukraine">Ukraine</option>
            <option value="United Kingdom (UK)">United Kingdom (UK)</option>
            <option value="Vatican City (Holy See)">Vatican City (Holy See)</option>
          </select>
        </div>
        <ol>
          {filteredUploads.sort((a, b) => new Date(b.uploaddate) - new Date(a.uploaddate)).map((upload, index) => (
            <li key={index} onClick={() => handleFileClick(upload)}>
              <p style={{ display: "inline-block", marginRight: "50px" }}>Upload Date: {upload.uploaddate}</p>
              <p style={{ display: "inline-block", marginRight: "50px" }}>Category: {upload.category}</p>
              <p style={{ display: "inline-block", marginRight: "50px" }}>Country: {upload.country}</p>
              <p style={{ display: "inline-block", marginRight: "50px" }}>Author: {upload.author}</p>
              <p style={{ display: "inline-block", marginRight: "50px" }}>ID: {upload.id}</p>
            </li>
          ))}
        </ol>
      </div>
    </div>
  );
}

export default Search;

```
The API endpoint for this in Server.js looks like this:

```
app.get("/api/uploads/:fileId", async (req, res) => {
  const { fileId } = req.params;
  try {
    console.log([fileId]);
    const queryResult = await pool.query(
      "SELECT filename FROM uploads WHERE id = $1",
      [fileId]
    );
    if (queryResult.rows.length > 0) {
      const { filename } = queryResult.rows[0];
      const filePath = path.join(__dirname, "uploads", filename);
      res.sendFile(filePath);
    } else {
      res.status(404).json({ message: "File not found" });
    }
  } catch (err) {
    console.error(err);
    res.status(500).json({ message: "Internal server error" });
  }
});
```
I have installed DocViewer on the front-end. My guess is that the problem originate from a miss config of the end point and also what the server should diplay, not JSON but PDF. Or that the mounting somehow gets stuck in a loop and closes the connection to early.

I have this error showing when trying to open a PDF file:

```
ERROR
signal is aborted without reason
    at http://localhost:3000/static/js/bundle.js:23248:18
    at safelyCallDestroy (http://localhost:3000/static/js/bundle.js:43291:9)
    at commitHookEffectListUnmount (http://localhost:3000/static/js/bundle.js:43429:15)
    at commitPassiveUnmountOnFiber (http://localhost:3000/static/js/bundle.js:45051:15)
    at commitPassiveUnmountEffects_complete (http://localhost:3000/static/js/bundle.js:45031:11)
    at commitPassiveUnmountEffects_begin (http://localhost:3000/static/js/bundle.js:45022:11)
    at commitPassiveUnmountEffects (http://localhost:3000/static/js/bundle.js:44976:7)
    at flushPassiveEffectsImpl (http://localhost:3000/static/js/bundle.js:46797:7)
    at flushPassiveEffects (http://localhost:3000/static/js/bundle.js:46751:18)
    at http://localhost:3000/static/js/bundle.js:46566:13
```
This is the screen after the error at the ViewPdf.jsx page:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0qxh8rxa6dzp9t8g3r6u.png)
It reads: You need to enable JavaScript to run this app.

As this is my first attempt with Node.js any suggestions are well appreciated. Thanks !