點燈坊

失くすものさえない今が強くなるチャンスよ

Axios 呼叫 PUT REST API

Sam Xiao's Avatar 2024-02-18

axios.put() 可簡單呼叫 PUT REST API。

Version

Vue 3.4
Axios 1.6.7

PUT

App.vue

<template>
  <ul>
    <li v-for="item in todos" :key="item.id">
      <span v-if="!item.isEdit">
        <span>{{ item.todo }}</span>
        <button @click="onEdit(item)">edit</button>
      </span>
      <span v-else>
        <input type="text" v-model="item.todo" />
        <button @click="onSave(item)">save</button>
      </span>
    </li>
  </ul>
</template>

<script setup>
import axios from 'axios'
import { ref, onMounted } from 'vue'

let todos = ref([])

onMounted(async () => {
  let url = 'http://localhost:3000/todos'

  try {
    let { data } = await axios.get(url)
    todos.value = data
  } catch (e) {
    console.error(e)
  }
})

let onEdit = (item) => {
  item.isEdit = true
}

let onSave = async (item) => {
  item.isEdit = false

  let url = `http://localhost:3000/todos/${item.id}`

  let body = {
    isCompleted: item.isCompleted,
    todo: item.todo
  }

  try {
    let { data } = await axios.put(url, body)
    return data
  } catch (e) {
    console.error(e)
  }
}
</script>

Line 2

<ul>
  <li v-for="item in todos" :key="item.id">
    <span>{{ item.todo }}</span>
  </li>
</ul>
  • v-for :列舉 todos state

Line 4

<span v-if="!item.isEdit">
  <span>{{ item.todo }}</span>
  <button @click="onEdit(item)">edit</button>
</span>
  • v-if:若是 非編輯模式,則直接顯示 todo
  • Button 此時為 edit

Line 8

<span v-else>
  <input type="text" v-model="item.todo" />
  <button @click="onSave(item)">save</button>
</span>
  • v-else:若是 編輯模式,則以 <input> 顯示 todo
  • Button 此時為 save

Line 17

import axios from 'axios'
  • 引用 Axios

Line 20

let todos = ref([])
  • todos state:儲存所有 todo

Line 22

onMounted(async () => {
  let url = 'http://localhost:3000/todos'

  try {
    let { data } = await axios.get(url)
    todos.value = data
  } catch (e) {
    console.error(e)
  }
})
  • onMounted():呼叫 GET REST API function 取得所有 todos
  • url 傳入 axios.get() 呼叫 GET REST API
  • axios.get() 所回傳的資料都放在 data property 下,可使用 { data } 直接 Object Destructure
  • Axios 回傳為 Promise,可使用 try catch 做 error handling

Line 33

let onEdit = (item) => {
  item.isEdit = true
}
  • 編輯一筆 todo
  • 將 item 的 isEdit 設定為 true 表示為 編輯模式,此時 button 會改為顯示 save

Line 37

let onSave = async (item) => {
  item.isEdit = false

  let url = `http://localhost:3000/todos/${item.id}`

  let body = {
    isCompleted: item.isCompleted,
    todo: item.todo
  }

  try {
    let { data } = await axios.put(url, body)
    return data
  } catch (e) {
    console.error(e)
  }
}
  • 儲存一筆 todo
  • 將 item 的 isEdit 設定為 false 表示為 非編輯模式,此時 button 會改為顯示 edit
  • urlbody 傳入 axios.put() 呼叫 PUT REST API

API Function

App.vue

<template>
  <ul>
    <li v-for="item in todos" :key="item.id">
      <span v-if="!item.isEdit">
        <span>{{ item.todo }}</span>
        <button @click="onEdit(item)">edit</button>
      </span>
      <span v-else>
        <input type="text" v-model="item.todo_" />
        <button @click="onSave(item)">save</button>
      </span>
    </li>
  </ul>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { getTodos, saveTodo } from '@/api/todos.js'

let todos = ref([])

onMounted(async () => (todos.value = await getTodos()))

let onEdit = (item) => {
  item.isEdit = true
}

let onSave = async (item) => {
  item.isEdit = false
  await saveTodo(item)
}
</script>

Line 18

import { getTodos, saveTodo } from '@/api/todos.js'
  • api 目錄引用 todos.js 內的 getTodos()saveTodo()

Line 22

onMounted(async () => (todos.value = await getTodos()))
  • 呼叫 getTodos() API function 取得所有 todos

Line 28

let onSave = async (item) => {
  item.isEdit = false
  await saveTodo(item)
}
  • 儲存一筆 todo
  • 最後呼叫 saveTodo() API function 儲存 todo

todos.js

import axios from 'axios'

export let getTodos = async () => {
  let url = 'http://localhost:3000/todos'

  try {
    let { data } = await axios.get(url)
    return data
  } catch (e) {
    console.error(e)
  }
}

export let saveTodo = async (item) => {
  let url = `http://localhost:3000/todos/${item.id}`

  let body = {
    isCompleted: item.isCompleted,
    todo: item.todo
  }

  try {
    let { data } = await axios.put(url, body)
    return data
  } catch (e) {
    console.error(e)
  }
}

Line 1

import axios from 'axios'
  • 引用 Axios

Line 3

export let getTodos = async () => {  
}
  • export:將 getTodos() 匯出,如此其他地方才能使用 import 將此 function 匯入

Line 6

try {
  let { data } = await axios.get(url)
  return data
} catch (e) {
  console.error(e)
}
  • axios.get() 所回傳的資料都放在 data property 下,可使用 { data } 直接 Object Destructure
  • 因為 getTodos() 是 function,所以要有回傳值,至於要不要接收回傳值則由使用端的 .vue 決定

Line 14

export let saveTodo = async (item) => {
}
  • export:將 saveTodo() 匯出,如此其他地方才能使用 import 將此 function 匯入

Line 15

let url = `http://localhost:3000/todos/${item.id}`

let body = {
  isCompleted: item.isCompleted,
  todo: item.todo
}

try {
  let { data } = await axios.put(url, body)
  return data
} catch (e) {
  console.error(e)
}
  • urlbody 傳入 axios.put() 呼叫 PUT REST API
  • axios.put() 所回傳的資料都放在 data property 下,可使用 { data } 直接 Object Destructure
  • 因為 saveTodo() 是 function,所以要有回傳值,至於要不要接收回傳值則由使用端的 .vue 決定

Conclusion

  • 實務上不建議將呼叫 API 寫在 .vue 內,因為 API 常常會被不同 component 或 view 重複呼叫,建議獨立抽成 API function
  • 實務上不建議將 function 包在 Object,然後匯出 Object,而是單獨 export 出 function,如此有助於 Vite 的 Tree Shaking