Using Redux to Fetch from API in the Client

In this article we're going to work on the express endpoint that serves the markdown. By the end of this lesson we'll have our posts displaying again in the client.

We're going to start where we left off in the last article.
If you need to catch up:

git clone https://github.com/lawwantsin/webpack-course.git
cd webpack-course
git checkout redux-client
npm install

Missing Image

Markdown Content API

We're going to need a few new packages. Let's use the same packages that are used in the markdown-with-front-matter-loader so it will be consistent with the way webpack is doing it.

In our terminal:

npm i marked yaml-front-matter

Now in express.js, let's import these and fs. We'll put the attempt in a try block. This will allow us to bail out if the slug doesn't match a file in our folders. If fs.readFile can't find the file, it will return a 404 in the response.

import marked from "marked"
import fs from "fs"
import { loadFront } from "yaml-front-matter"

server.get("/api/articles/:slug", (req, res, next) => {
  try {
    const site = req.hostname.split(".")[0]
    const { slug } = req.params
    if (!slug) {
      throw new Error("No slug provided")
    }
    const file = path.resolve(__dirname, `../../data/${site}/${slug}.md`)
    fs.readFile(file, "utf8", (err, data) => {
      if (err) {
        res.status(404).send(err)
        return
      }
      const obj = yaml.loadFront(data)
      obj.__content = marked(obj.__content)
      res.json(obj)
    })
  } catch (err) {
    res.status(404).json(err)
  }
})

If we do find the file. We grab the yaml and the markdown content into the response, matching what we got from our markdown loader. So when we go to the Article component, very little needs to change.

In Article.js we connect the store to the component. We spread the object state.content over the Article as props and they line up perfectly:

export default connect(state => ({
  ...state.content
}))(Article)

Hot Reloading Reducers

In store.js:

export default initialState => {
  const store = createStore(fetchArticle, enhancer)
  if (module.hot) {
    module.hot.accept("./reducers", () =>
      store.replaceReducer(require("./reducers").fetchArticle)
    )
  }

  return store
}

In Sum

We did it. We setup a client API for fetching our posts. You should see it pulling in the Article once the client code loads. It's still not rendering to server tho.

git checkout redux-client-final

Up Next

Now let's do the same for our server side. This is not as hard as some would make it out to be. But it does require an effective use of Promises.