Part 2 – Static POST Handler

Try adding a Reminder to "Shop for groceries" by pressing "+", filling out the input field and hitting enter. You should see another error:

Failing request

If you check your console you'll see this message:

Mirage: Your app tried to POST '/api/reminders', but there was no route defined to handle this request.

Let's mock out this POST request. Start by copying the highlighted lines into your server's routes() hook:

createServer({
  routes() {
    this.get("/api/reminders", () => ({
      reminders: [
        { id: 1, text: "Walk the dog" },
        { id: 2, text: "Take out the trash" },
        { id: 3, text: "Work out" },
      ],
    }))

    this.post("/api/reminders", (schema, request) => {
      let attrs = JSON.parse(request.requestBody)
      console.log(attrs)
      debugger
    })
  },
})

We're using this.post to handle this request. We're also using the request argument to access the data sent over from our application. The request.requestBody property contains the request body as a JSON string, so after parsing it we log it to the console.

After saving this new code, make sure your JavaScript console is open and try adding a Reminder to "Shop for groceries" again. The DevTools should hit the debugger statement in your route handler, and you should see the object { text: "Shop for groceries" } logged to your console.

Failing request

Being able to use the DevTools to help you write and debug route handlers right alongside your frontend code is a key part of what makes Mirage so productive.

Press the Play button to allow JavaScript to continue execution. Mirage will respond successfully with a 201 status code, but the app will crash with an error:

Cannot read property 'id' of undefined

If you scroll up your console to the first error, here's a screenshot of what you should see:

First error

Our app is expecting the API server to respond with an object that looks like this:

{
  "reminder": {
    "id": 4,
    "text": "Shop for groceries"
  }
}

but right now we're not returning anything from our route handler.

Let's return an object that looks like this. We'll use the attrs from our request, and also add in an id key. We'll use the number 4 as the ID since our existing reminders use IDs 1 through 3.

Here's our new route handler – go ahead and copy this into your server:

this.post("/api/reminders", (schema, request) => {
  let attrs = JSON.parse(request.requestBody)
  attrs.id = 4

  return { reminder: attrs }
})

Now add a Reminder to "Shop for groceries" – there's no more errors, and the app updates correctly!

...unless you try to create a second todo! Try adding a second Reminder to "Clean the bathroom". React will throw an error:

Encountered two children with the same key, '4'.

Instead of hard-coding the ID as 4, let's use an incrementing number:

import { createServer } from "miragejs"

export default function () {
  return createServer({
    routes() {
      this.get("/api/reminders", () => ({
        reminders: [
          { id: 1, text: "Walk the dog" },
          { id: 2, text: "Take out the trash" },
          { id: 3, text: "Work out" },
        ],
      }))

      let newId = 4
      this.post("/api/reminders", (schema, request) => {
        let attrs = JSON.parse(request.requestBody)
        attrs.id = newId++

        return { reminder: attrs }
      })
    },
  })
}

Now our app works no matter how many reminders we create. If you inspect the Mirage response, you should see the new incrementing IDs being returned from our route handler.

First error

Takeaways

  • Mirage can handle POST requests
  • Route handlers can use data from the request when constructing the response
  • Route handlers should faithfully recreate important details of production server endpoints, like unique IDs