# 🏅 Day 16 - TodoList API & Promise ![截圖 2024-01-23 下午2.01.58](https://hackmd.io/_uploads/BktP8C3Fp.png) 學習一定的階段之後,相信大家也已經吸收到許多關於 TypeScript 的知識了,那麼接下來就是將這些知識給運用在開發上的練習!透過這些練習也能讓大家對於主線任務的進行更加掌握和熟悉! 這邊使用的是六角的 TodoList API 幫助大家練習~ 1. API 網址:https://todolist-api.hexschool.io/ 2. API 文件:https://todolist-api.hexschool.io/doc/ 通通做好做滿,新增、編輯、刪除應有盡有,讓同學們可從中思考,如果有相同程式邏輯的程式碼,該如何進行優化~ ## 建立 Vue with TypeScript 專案 首先我們要來建立一個 Vue 的專案,並且支援 TypeScript 的語法,同學可以自己選用習慣的方式來建立專案,或是也可以參考[第一天](https://hackmd.io/@hex-course/SyGd4x8Aee)的任務內容,使用 Vite 來將專案給初始化起來~ ```shell $ npm create vite@latest ... (輸入專案名稱) Select a framework >> Vue Select a variant >> TypeScript ... (按照預設選項即可) ``` 建立完成後進入到專案內,可以透過 `npm run dev` 讓專案執行起來,也可以運用先前課程學到的內容,針對 `tsconfig` 的部分自行調整~ ## 實作時間 請使用 TodoList API 進行開發並嘗試導入 TypeScript 進行優化,本日可以聚焦在如何設計關於 API 的模組化、泛型。 參考 API 文件當中各個 API 的請求、回傳格式,設計一個通用的函式 `apiFetch` 讓後續的 API 呼叫可以透過這個 `apiFetch` 來統一處理,並且支援請求和回傳的型別格式。 另外關於呼叫 API 的工具,除了利用原生的 `fetch` 之外,也可以嘗試使用外部套件如 `axios` 等來整合~ ```ts // src/api/api.ts export const apiFetch = async () => { // ... }; // 範例 API 設計 // src/api/user.ts export const register = async () => { const response = await apiFetch("users/sign_up", ...); return response; }; // 此處帶入的參數、形式會根據 apiFetch 的設計而有所不同 export const login = async () => { const response = await apiFetch("users/sign_in", ...); return response; }; ``` <!-- 參考範例: type ApiArgs<T> = { endpoint: string; method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH"; requestBody?: T; }; const apiFetch = async <T, U>(args: ApiArgs<T>): Promise<U> => { // 一般會將 baseUrl 使用環境變數做管理,這邊為了簡化範例故直接寫死在函式當中 const baseUrl = "https://todolist-api.hexschool.io"; const url = `${baseUrl}/${args.endpoint}`; try { const response = await fetch(url, { method: args.method, body: args.requestBody ? JSON.stringify(args.requestBody) : null, headers: { "Content-Type": "application/json", Authorization: localStorage.getItem("token") || "", }, }); const responseData = (await response.json()) as U; return responseData; } catch (error) { throw new Error("Error occurred fetching: " + String(error)); } }; type Status = { status: boolean; }; type signupData = { email: string; password: string; nickname: string; }; type signinData = Omit<signupData, "nickname">; type signupResponse = { uid: string; } & Status; type signinResponse = { exp: number; nickname: string; token: string; } & Status; const register = async (signupData: signupData) => { const response = await apiFetch<signupData, signupResponse>({ endpoint: "users/sign_up", method: "POST", requestBody: signupData, }); return response; }; const login = async (signinData: signinData) => { const response = await apiFetch<signinData, signinResponse>({ endpoint: "users/sign_in", method: "POST", requestBody: signinData, }); return response; }; -->