该系列是为了让看过Vue官方文件或学过Vue但是却不知道怎麽下手去重构现在有的网站而去规画的系列文章,在这边整理了许多我自己使用Vue重构很多网站的经验分享给读者们。
我们在开发网页的时候一定会处理到 RESTful API 的串接,绝大多数我们都会将 RESTful API 给写在 component 里面去做操作,但是这样的做法在具有一定规模的平台上面是非常难以管理跟维护的。
在这边我选用 axios
来作为我处理非同步的工具。
import { ref, onMounted } from "vue"
import axios from "axios"
export default {
setup() {
const Data = ref([]);
onMounted(()=> {
axios.get('https://test.api/api/item')
.then(res => {
Data.value = res;
})
.catch(error => {
console.log("handle error =>", error);
})
})
return {
Data
};
},
}
我这边列出几个常见到的 RESTful API 直接写在 component 里面的缺点:
headers
里面塞入物件的时候,会重复的去写这个物件,要改的时候会变很麻烦。所以实际上专案要管理 API,最後就是把 API 的部分给抽离出来,不要直接写在里面,你会说我会把前面的domain 拉出去变成变数或是集中把所有的 API 放入阵列里面再去利用索引呼叫做管理,甚至可以统一拉到 Vuex去管理使用 API 等方法,但我都觉得这类的方法都不会是最佳管理 API 的最佳作法,相信我! 这类的管理的方式我做了许多的尝试…,不同 domain 的 API 管理上面相对来说相对难度也会提高,除了程序可读性以外,还要好维护,考量到许多因素後,我来分享一下我是怎麽做的。
首先开一个名字叫 api
的资料夹,里面新增一个 index.js
,作为进入点,再来开始分类你的API。
我今天有一个部落格平台要做,然後有三个项目的功能要做,三个项目的 API 都各自散落在不同的机器,每个项目都有数个API 需要使用到。
// user.js
const userRequest = axios.create({
baseURL: 'https://api/user/'
})
export const postUserLogin = data => userRequest.post('/signIn', data)
export const postUserLogout = data => userRequest.post('/signOut', data)
export const postUserSignUp = data => userRequest.post('/signUp', data)
// article.js
const articleRequest = axios.create({
baseURL: 'https://api/article/'
})
export const getArticleItem = () => articleRequest.get('/ArticleItem')
export const postArticleMsg = data => articleRequest.post('/ArticleMsg', data)
export const postArticleLink = data => articleRequest.post('/ArticleLink', data)
// search.js
const searchRequest = axios.create({
baseURL: 'https://api/search/'
})
export const getSearch = data => searchRequest.get(`/Search?searchdata=${data}`)
export const getSearchType = () => searchRequest.get(`/SearchType`)
axios.create
去创造一个实体,再利用变数去接这个实体,get
或是post
,然後在 export
出去给外面的 js去 import
就好。再来我们在 api/index.js
整合这 3 个档案的 API
import {
postUserLogin,
postUserLogout,
postUserSignUp
} from "./user.js"
import {
getArticleItem,
postArticleMsg,
postArticleLink
} from "./article.js"
import {
getSearch,
getSearchType
} from "./search.js"
export const apiPostUserLogin = postUserLogin
export const apiPostUserLogout = postUserLogout
export const apiPostUserSignUp = postUserSignUp
export const apiGetArticleItem = getArticleItem
export const apiPostArticleMsg = postArticleMsg
export const apiPostArticleLink = postArticleLink
export const apiGetSearch = getSearch
export const apiGetSearchType = getSearchType
接下来我们要使用的时候只要import
api 这个资料夹就好了,像这样就可以确保你 API 来源都是同一个进入点
import { apiGetArticleItem, apiGetSearch } from "../api";
实际在 component 内使用会像这样。
import { apiGetArticleItem, apiGetSearch } from "../api"
import { ref, onMounted } from "vue"
export default {
setup() {
const getData = async () => {
try {
const item = await apiGetArticleItem()
const search = await apiGetSearch()
// 其他的处理
} catch (err) {
console.error(err)
}
}
onMounted(()=> {
getData()
})
return {}
},
}
这样的方式一样可以在 Vuex 或是透过 composition api 来引入使用。
import { apiGetArticleItem, apiGetSearch } from "../api"
import { createStore } from 'vuex'
const store = createStore({
state () {
return {
item: [],
search: {},
}
},
actions: {
async getDate({commit}, newId) {
try {
const item = await apiGetArticleItem()
const search = await apiGetSearch()
commit("GET_DATA", { item: item.data, search: search.data })
} catch (err) {
console.error(err)
}
},
},
mutations: {
GET_DATA (state, payload) {
state.item = payload.item
state.search = payload.search
}
}
})
axios.create
所创造出来的实体你可以透过变数去重新给予这个实体一个新的名字,然後透过命名规则的方式来区分你的 api 来分类,在每个 import 的 js 档案只要透过命名规则就可以清楚知道这个 api 目前是从哪个机器跟分类的。.then
还有.catch
等方法,使用 try catch
code会更简洁。axios 有提供拦截 request 与 response 的方法,可以让我们在发送 request 前或是 response 回来之後统一的去做一些处理,像是送出资料的时候检查有没有 token 或是资料回来了检查API 是否有错误或是status code 是否不是 200 要做 Error handling。
我们可以在你axios.create
那个档案里面这样用,以 search.js
为例
// search.js
const searchRequest = axios.create({
baseURL: 'https://api/search/'
})
// 拦截 API request 的请求
searchRequest.interceptors.request.use(request=> {
// API送出前可以做最後的处理
request.headers['Authorization'] = "你的任何想塞进去的东西";
return request;
}, error=> {
// 如果送出前失败了,这边就可以做一些处理
return Promise.reject(error);
});
// 拦截 API response 的回传
searchRequest.interceptors.response.use(response => {
// 这边可以对回来的资料先进行验证处理,再来决定要不要把资料给吐出去
return Promise.resolve(response);
}, error => {
// 这边当API发生错误的时候就可以处理 Error handling
return Promise.reject(error.response.data);
})
export const getSearch = data => searchRequest.get(`/Search?searchdata=${data}`)
export const getSearchType = () => searchRequest.get(`/SearchType`)
我自己对於这样的统一处理 Error handling 可以说是非常的喜欢,大家可以试试看。
Axios GitHub : https://github.com/axios/axios
之前我有在社群分享过我在规划专案使用 Vuex 跟 API 的架构,里面也有提到独立管理 API 的部分,分享一下简报给各位读者当参考。
https://slides.com/mikecheng1208/deck-1
Ps. 购买的时候请登入或注册该平台的会员,然後再使用下面连结进入网站点击「立即购课」,这样才可以让我获得更多的课程分润,还可以帮助我完成更多丰富的内容给各位。
我有开设了一堂专门针对Vue3从零开始教学的课程,如果你觉得不错的话,可以购买我课程来学习
https://hiskio.com/bundles/9WwPNYRpz?s=tc
那如果对於JS基础不熟的朋友,我也有开设JS的入门课程,可以参考这个课程
https://hiskio.com/bundles/b9Rovqy7z?s=tc
Mike 的 Youtube 频道
Mike的medium
MIke 的官方 line 帐号,好友搜寻 @mike_cheng
<<: Chapter1 - 补充 CORS + autoplay政策 + requestAnimeFrame致命缺点
>>: [Java Day02] 我的第一支Java程序 & 程序卡与范例档的使用
ModernWeb 是台湾网站技术人的年度盛会,有许多 Web 技术高手分享经验, 今年同样采线上的...
订阅patreon即可看到更多文章 https://www.patreon.com/wade3c ...
我可以吃,啊不对,是ISO27001可以吃,更不对XDDD"是赚来的钱钱可以买好吃的~(冷...
前半段讲python讲得差不多惹XDD 终於进入机器学习篇章(打开全新的一页的感觉),接着让我们好好...
昨天威尔猪示范了按钮的制作,很多小伙伴应该看完就崩溃了,样式设计很弹性没错,但写一个小小的按钮 +...