# 🏅 Day 16 - TodoList API & Promise

學習一定的階段之後,相信大家也已經吸收到許多關於 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;
};
-->