From 126df6e3f838627dab55465af7f71db474fe88b6 Mon Sep 17 00:00:00 2001 From: cp-20 Date: Sat, 15 Jun 2024 22:50:05 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20API=E5=91=BC=E3=81=B3=E5=87=BA=E3=81=97?= =?UTF-8?q?=E3=81=AE=E3=83=A9=E3=83=83=E3=83=91=E3=83=BC=E3=82=92=E4=BD=9C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/features/api.ts | 203 +++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 frontend/src/features/api.ts diff --git a/frontend/src/features/api.ts b/frontend/src/features/api.ts new file mode 100644 index 0000000..4570b0b --- /dev/null +++ b/frontend/src/features/api.ts @@ -0,0 +1,203 @@ +export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'; + +export const fetchApi = async ( + method: HttpMethod, + path: string, + option?: { parameters?: Record; body?: Record }, +) => { + const bodyObj = option?.body && { + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(option?.body), + }; + const parameterStr = option?.parameters + ? new URLSearchParams(JSON.parse(JSON.stringify(option?.parameters))).toString() + : ''; + const res = await fetch(`/api${path}?${parameterStr}`, { + method, + ...bodyObj, + }); + const data = await res.json(); + return data; +}; + +export type Expand = T extends infer O ? { [K in keyof O]: O[K] } : never; + +export type CreatedPost = { + /** + * 変換元のメッセージ + */ + original_message: string; + /** + * 変換後のメッセージ + */ + converted_message: string; + /** + * UUID + */ + id: string; + /** + * 投稿時刻 + */ + created_at: string; + /** + * リプライのとき、親のID。そうでなければ自身のID + */ + parent_id?: string; + /** + * リプライのとき、そのおおもとのID。そうでなければ自身のID + */ + root_id: string; +}; + +export type Post = Omit & { + /** + * 投稿したユーザー名 + */ + user_name: string; + /** + * リアクションのリスト + */ + reactions: Reaction[]; + /** + * 自分がリアクションしたリアクションIDのリスト + */ + my_reactions: number[]; +}; +export type PostWithoutParents = Omit; +export type PostDetail = PostWithoutParents & { + /** + * 全ての祖先投稿で、古い順 + */ + ancestors: Array<{ + post: Omit; + children_count: number; + }>; + /** + * 1個下の子投稿で、新しい順 + */ + children: Array<{ + post: Omit; + children_count: number; + }>; +}; + +export type Reaction = { + /** + * リアクションID + */ + id: number; + /** + * カウント + */ + count: number; +}; +export type ReactionDetail = { + /** + * リアクションID + */ + id: number; + /** + * リアクションしたユーザーのID + */ + users: string[]; +}; + +export type CreatePostBody = { + /** + * メッセージ + */ + message: string; + /** + * リプライのとき、親のID。そうでなければundefined + */ + parent_id?: string; +}; +export type CreatePostResponse = CreatedPost; +export const createPost = async (body: CreatePostBody): Promise => { + return fetchApi('POST', '/posts', { body }); +}; + +export type GetPostsParameters = { + /** + * 取得件数。デフォルト30 + */ + limit?: number; + /** + * このIDの投稿より後に投稿されたものを取得する。指定されない場合は、最新のものからlimit件取得する + */ + after?: string; + /** + * リポストのやつを含むかどうか。デフォルトはfalse + */ + repost?: boolean; +}; +export type GetPostsResponse = Array< + Expand< + Post & { + /** + * リポストの場合はリポストしたユーザーの名前 + */ + repost_user?: string; + } + > +>; +export const getPosts = async ({ + limit, + after, + repost, +}: GetPostsParameters): Promise => { + return fetchApi('GET', '/posts', { + parameters: { limit: limit?.toString() ?? '30', after, repost: repost?.toString() ?? 'false' }, + }); +}; + +type GetPostResponse = Expand; +export const getPost = async (postId: string): Promise => { + return fetchApi('GET', `/posts/${postId}`); +}; + +export type PostReactionResponse = Reaction[]; +export const postReaction = async (postId: string, reactionId: number) => { + return fetchApi('POST', `/posts/${postId}/reactions/${reactionId}`); +}; + +export type DeleteReactionResponse = Reaction[]; +export const deleteReaction = async (postId: string, reactionId: number) => { + return fetchApi('DELETE', `/posts/${postId}/reactions/${reactionId}`); +}; + +export type GetReactionsResponse = ReactionDetail[]; +export const getReactions = async (postId: string) => { + return fetchApi('GET', `/posts/${postId}/reactions`); +}; + +export type GetTrendResponse = Array; +export const getTrend = async () => { + return fetchApi('GET', '/trend'); +}; + +export type GetUserResponse = { + /** + * ユーザーID + */ + user_name: string; + /** + * 投稿数 + */ + post_count: number; + /** + * リアクションした数 + */ + reaction_count: number; + /** + * リアクションされた数 + */ + get_reaction_count: number; + /** + * 投稿のリスト + */ + posts: Post[]; +}; +export const getUser = async (userId: string) => { + return fetchApi('GET', `/user/${userId}`); +};