Kamil Staszewski
Kamil Staszewski

Reputation: 346

Express.js routing 404

I have a problem with dynamic routing with express.js in my react app. Everything works on localhost but when im deploying i get 400. Here's link: https://shoppyshop.herokuapp.com/item/1

As you see in console there is 400 error. My goal is to fetch data properly from that route that i did setup in my index.js of express.

app.get('/api/item/:id', function (req, res) {
    let find = data.filter((el => {
        return el.product.id == req.params.id
    }))
    res.json(find)
    console.log('found item')
})

I understand that there is a problem with express. Im probably using wrong method so it wants to fetch icon and rest files from wrong path. Was googling, couldn't find similar problem. How to fix that? Here's component that fetches data:

export default class ItemInfo extends Component {
    constructor(props) {
      super(props)

      this.state = {
         data: []
      }
    }

    componentDidMount = () => {
        axios.get(`/api/item/${this.props.match.params.id}`)
            .then(res => {
                const data = res.data;
                this.setState({
                    data,
                    fetched: true
                })
            })
    }

  render() {
      console.log(this.props.match.params.id)
    return (
      <div className="App">
      <SideBar pageWrapId={"mainpage"} outerContainerId={"MainPage"} />
      <div id="mainpage">
          <TopBar />
          <More data={this.state.data} fetched={this.state.fetched}/>
          <Footer />            
      </div>
  </div>
    )
  }
}

Here's branch with code that im working on: https://github.com/KamilStaszewski/shoppy/tree/itemrouting/client

My express.js file:

const express = require('express');
const path = require('path');
const data = require('./apiData');

const app = express();

// Serve the static files from the React app
app.use(express.static(path.join(__dirname, 'client/build')));
app.disable('etag');


app.get('/category/:category', function (req, res) {
    let find = data.filter((el => {
        return el.product.category == req.params.category
    }));
    res.json(find);
    console.log('found category');
});

app.get('/api/item/:id', function (req, res) {
    let find = data.filter((el => {
        return el.product.id == req.params.id
    }))
    res.json(find)
    console.log('found item')
})

// An api endpoint that returns a short list of items
app.get('/api/data', (req, res) => {
    var questions = data
    res.json(questions);
    console.log('Sent list of items');

});




// Handles any requests that don't match the ones above
app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname + '/client/public/index.html'));
});

const port = process.env.PORT || 5000;
app.listen(port);

console.log('App is listening on port ' + port);

UPDATE:

After many commits and pushing I found the answer. I dont know if its right way, but it works. The problem was with:

app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname + '/client/public/index.html'));
});

Instead of serving index from build i was serving index from public which had no js inside it. To make it works i changed to:

app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname + '/client/build/index.html'));
});

Now it works.

Upvotes: 0

Views: 174

Answers (1)

Pytth
Pytth

Reputation: 4176

I am pretty sure that this is a problem with how you are serving static files in express.

From the express docs:

app.use('/static', express.static('public'))

Now, you can load the files that are in the public directory from the /static path prefix.

http://localhost:3000/static/images/kitten.jpg

http://localhost:3000/static/css/style.css

http://localhost:3000/static/js/app.js

http://localhost:3000/static/images/bg.png

http://localhost:3000/static/hello.html

However, the path that you provide to the express.static function is relative to the directory from where you launch your node process. If you run the express app from another directory, it’s safer to use the absolute path of the directory that you want to serve:

app.use('/static', express.static(path.join(__dirname, 'public')))

Your code has the following for serve static:

app.use(express.static(path.join(__dirname, 'client/build')));

So if I am reading this correctly, as I look at your code, I would understand that to be the following:

When you have an request that comes in for /, the rest of the call will search within client/build for the data. In your case, for your get request to /api/item/:id, that would probably be read by your server to try and find a static file in client/build/api/item/:whatevertheitemidis.

Instead, to serve static files, I would perhaps consider putting them in a directory called 'public' or something, and change your serve static to something like:

app.use('/public', express.static(path.join(//Wherever you keep your static files)));


With this all said, I may have been mistaken regarding some of the nuances of express.static so be sure to checkout the documentation. Either way, I hope to at least have pointed you in the right direction. If you comment out your serve static line and make a request with postman, you should see it working as expected.


UPDATE

I took a look at your code and noticed a couple of things:

  1. I just pulled down your code and the endpoints are working. I tried http://localhost:5000/api/data and it provided the expected data.

  2. It looks like your problem with serving static assets -- such as your favicon -- is because of the %PUBLIC_URL%/ part of your favicon url in your html. So far as I can find, there is nothing in your code that would translate that to an actual route. As soon as I turned that to /favicon, everything started working as expected.

Upvotes: 2

Related Questions