Is there a way to serve files to browser and data to rest requests using the same endpoint?

Viewed 38

I've followed this 7 hour tutorial on creating a blog almost to. There is one step that I skipped, because I did not want to use the separate client/server hosting that the tutorial suggests. Instead, I have a single heroku server that serves the client out of the public server:

const app = express();
app.use(express.static('public'))
app.use('/posts', postRoutes);
app.use('/user', userRoutes)

You can see that the app also serves some rest requests to the /posts and /user paths. However, the tutorial also led me to add these paths into the url client-side.

For example, you can access my app at (https://blog-tutorial-888.herokuapp.com), but you will be immediately "redirected" to (https://blog-tutorial-888.herokuapp.com/posts).

I say "redirected" because on the client side, it appears that you are at that site, and the purpose is so that you can do things like navigate to the next page, which will be at (https://blog-tutorial-888.herokuapp.com/posts?page=2).

But if you were to actually go to these links, or refresh the page, you will be hit with the result of the rest request, which is a giant block of text (and this is obviously because I have app.use('/posts', postRoutes)).

Is there a way to get around this somehow? Somehow serve both the html and the rest request at this endpoint?

1 Answers

To have a single server that severs the front and data trough a REST API, you would need to differentiate the paths, for example by adding an /api to urls for getting data, like so:

app.use('/api/posts', postRoutes);
app.use('/api/user', userRoutes);

And then below all your /api handlers add following lines so that for every other request you send that HTML that would load React bundle:

app.get("/*", (req, res) => {
  // Make sure it's the correct path to the build folder
  res.sendFile(path.join(__dirname, "../client/build/index.html"));
});

Of course don't forgot to add /api in your front end query urls as well, not the routes setup:

fetch("/api/posts")
// or
axios.get("/api/posts")
Related