用兩支 API 實作新增資料與上傳檔案

  1. API 文件
    1. POST /user/:id
    2. POST /file
  2. 依照 API 文件寫 vuex
  3. 另一種不推薦的做法

實作新增資料與上傳檔案有兩種做法

  1. 開一支 API 處理新增使用者,設定成 multipart/form-data 就可以同時上傳檔案和使用者資料。
  2. 開一支上傳檔案的 API,處理檔案,另一支就處理要儲存到資料庫的使用者資料。上傳之後的 path 放在資料庫的任務就交給了前端。

在講的是第二種方法,想要在 POST User 時,先上傳大頭照,再把 path 放到使用者資料。

之後會專門寫一篇文章,講「多個動作的同步資料整理」。

API 文件

遇到這種 API,怎麼做呢?

POST /user/:id

request body

{
  name: 'chris',
  avatar: 'http://127.0.0.1/img/user_1.jpg'
}

**response 200 **

(略)

POST /file

request header

{
  'Content-Type': 'multipart/form-data'
}

request body

form-data

{
  file: (binary)
}

**response 200 **

{
  data: '/file/:file_path'
}

依照 API 文件寫 vuex

依前幾天建立的默契,可以知道

  1. state 要建立 file
state: {
  file: null
},
  1. mutations 要建立 file
mutations: {
  file(state, payload) {
    state.file = payload
  }
},
  1. getters 要建立 file
getters: {
  file: state => state.file
},

這些一定要做。

  1. 避免直接存取資料
  2. 需要時可以擋住格式不符
  3. 可以使用 devtool 的 hook
  4. 增加資料的抽象化

另外特別的地方

  1. 資料直送的情況,mutation 和 getters 的命名要相同。
  2. 資料有特別處理,會增加不同名字的 getters。

所以

要 file 可以用 $store.getters.file 就取得

@/store/actions.js

import backendAPI from '@/utility/backendAPI.js'

export default {
  async uploadFile({ commit, getters }) {
    const file = getters.file;
    const res = await backendAPI.formDataPOST(`/file`, { file })
    return res.data
  }
  // ...
}

src/store/user/actions.js

在 createUser 上面加上 uploadFile

import backendAPI from '@/utility/backendAPI.js'

export default {
  async createUser({ dispatch, getters }, { name }) {
    if (getters.file != null) {
  	  const res = await dispatch('uploadFile');
      await backendAPI.POST(`/user`, {
        name,
        avatar: res.data,
      });
    } else {
      await backendAPI.POST(`/user`, {
        name,
      });
    }
  },
  // ...
}

在新增時就可以直接

onSubmit() {
  this.$store.dispatch('createUser', this.$store.getters.user);
}

另一種不推薦的做法

直接在選取完檔案之後,就將檔案先上傳。而不是等到要新增人員時才上傳。

缺點: 在一次修改的過程中,不斷的換掉檔案,就會不斷的上傳,導致伺服器上的垃圾檔案會更新變多。