Building Api Mock Environment

# Building Environment

1. express
2. connect-api-mocker
3. axios
4. VueX
5. Impliment Todo App



## 1. express

> http://expressjs.com/en/starter/installing.html

### Hello world example

`$ npm install express`

▼

`$ mkdir api`
`$ touch api/index.js`

▼

`$ vim api/index.js`

▼

```js
// api/index.js
const express = require('express')
const app = express()
const port = 8080

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})

module.exports = {
  path: '/api',
  handler: app
}
```

▼

`$ vim nuxt.config.js`

▼

```js
// nuxt.config.js
export default {
  // ...
  serverMiddleware: ['../api']
}
```



## 2. connect-api-mocker

> https://github.com/muratcorlu/connect-api-mocker

### Using with Express

`$ npm install connect-api-mocker --save-dev`

▼

`$ vim api/index.js`

▼

```js
// api/index.js
const express = require('express')
const apiMocker = require('connect-api-mocker')
const app = express()

app.use('/api', apiMocker('mocks/api'))
app.listen(8080)

module.exports = {
  path: '/api',
  handler: app
}
```

▼

```
Endpoint not found on mock files:
```

#### Resolution

`$ mkdir -p __mock__/api/messages`
`$ touch __mock__/api/messages/GET.json`

▼

`$ vim __mock__/api/messages/GET.json`

▼

```json
{ "message": "hello, api" }
```

▼

`$ vim api/index.js`

▼

```js
// api/index.js
  // ...
  app.use('/api', apiMocker('mocks/api', '__mock__/api'))
```



## 3. axios

> https://axios.nuxtjs.org/

### Setup

`$ yarn add @nuxtjs/axios`

▼

`$ vim nuxt.config.js`

▼

```js
// nuxt.config.js
export default {
  // ...
  modules: ['@nuxtjs/axios']
}
```

### Usage

`$ vim pages/index.vue`

▼

```vuejs
// pages/index.vue
export default {
  // ...
  async asyncData({ $axios }) {
    const ip = await $axios.$get('/messages')
    console.log(ip)
    return { ip }
  }
}
```

▼

```
Uncaught (in promise) Error: Request failed with status code 404
```

#### Resolution

`$ vim nuxt.config.js`

▼

```js
// nuxt.config.js
export default {
  // ...
  axios: {
    prefix: '/api',
    proxy: true
  },
  proxy: {
    '/api/': 'http://localhost:8080'
  }
}
```



## 4. VueX

> https://ja.nuxtjs.org/docs/2.x/directory-structure/store

### モジュール

`$ mkdir store`
`$ touch store/todos.js`

▼

`$ vim store/todos.js`

▼

```js
// store/todos.js
export const state = () => ({
  list: []
})

export const mutations = {
  add(state, text) {
    state.list.push({
      text,
      done: false
    })
  },
  remove(state, { todo }) {
    state.list.splice(state.list.indexOf(todo), 1)
  },
  toggle(state, todo) {
    todo.done = !todo.done
  }
}
```

▼

`$ touch pages/todos.vue`

▼

`$ vim pages/todos.vue`

▼

```vuejs
// pages/todos.vue
<template>
  <ul>
    <li v-for="todo in todos" :key="todo.text">
      <input :checked="todo.done" @change="toggle(todo)" type="checkbox">
      <span :class="{ done: todo.done }">{{ todo.text }}</span>
    </li>
    <li><input @keyup.enter="addTodo" placeholder="What needs to be done?"></li>
  </ul>
</template>

<script>
import { mapMutations } from 'vuex'

export default {
  computed: {
    todos () {
      return this.$store.state.todos.list
    }
  },
  methods: {
    addTodo (e) {
      this.$store.commit('todos/add', e.target.value)
      e.target.value = ''
    },
    ...mapMutations({
      toggle: 'todos/toggle'
    })
  }
}
</script>

<style>
.done {
  text-decoration: line-through;
}
</style>
```

## 5. Impliment Todo App

`$ mkdir __mock__/api/todos`
`$ touch __mock__/api/todos/GET.json`

▼

`$ vim __mock__/api/todos/GET.json`

▼

```json
{ "todos":
  [
    {
      "text": "aaa",
      "done": true
    },
    {
      "text": "bbb",
      "done": false
    }
  ]
}
```

▼

`$ vim store/todos.js`

▼

```js
export const state = () => ({
  list: []
})
  
export const mutations = {
  add(state, data) {
    const list = Array.isArray(data) ? data : [{
      text: data,
      done: false
    }]
    list.forEach(data => {
      state.list.push(data)
    })
  },
  remove(state, { todo }) {
    state.list.splice(state.list.indexOf(todo), 1)
  },
  toggle(state, todo) {
    todo.done = !todo.done
  }
}

export const actions = {
   async fetch({ commit }) {
    const path = `/todos`
    const { todos } = await this.$axios.$get(path)
    commit('add', todos)
  }
}
```

▼

`$ vim pages/todos.vue`

▼

```vuejs
<template>
  <div>
    <ul>
      <li v-for="todo in todos" :key="todo.text">
        <v-checkbox
          v-model="checkedList"
          :class="{ done: todo.done }"
          :label="todo.text"
          :value="todo.text"
          @change="toggle(todo)"
        ></v-checkbox>
      </li>
      <li>
        <v-text-field @keyup.enter="addTodo" placeholder="What needs to be done?"></v-text-field>
      </li>
    </ul>
  </div>
</template>

<script>
  import { mapState, mapMutations } from 'vuex'
  export default {
    async fetch({ store, params }) {
      await store.dispatch('todos/fetch')
    },
    created() {
      this.todos.forEach(todo => {
        if (todo.done) this.checkedList.push(todo.text)
      })
    },
    data() {
      return {
        checkedList: []
      }
    },
    computed: {
      ...mapState ({
        todos: state => state.todos.list
      })
    },
    methods: {
      addTodo (e) {
        this.add(e.target.value)
        e.target.value = ''
      },
      ...mapMutations({
        toggle: 'todos/toggle',
        add: 'todos/add'
      })
    }
  }
</script>

<style>
  .done label {
    text-decoration: line-through;
  }
</style>
```