api.ts 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import assert from "assert";
  2. const API = process.env.NEXT_PUBLIC_API || "/api";
  3. export enum ApiMethods {
  4. GET = "GET",
  5. POST = "POST",
  6. PUT = "PUT",
  7. }
  8. export enum ApiResulState {
  9. SUCCESS,
  10. ERROR,
  11. }
  12. type SuccessApiResult = {
  13. state: ApiResulState.SUCCESS;
  14. message: string;
  15. user: User;
  16. };
  17. type FailureApiResult = { state: ApiResulState.ERROR; error: string };
  18. export type FetchApiResult = SuccessApiResult | FailureApiResult;
  19. type FetchApi = <T>(
  20. path: string,
  21. method: ApiMethods,
  22. body: T
  23. ) => Promise<FetchApiResult>;
  24. const fetchApi: FetchApi = async (path, method, body) => {
  25. try {
  26. const response = await fetch(`${API}${path}`, {
  27. method: method,
  28. body: JSON.stringify(body),
  29. headers: { "Content-Type": "application/json" },
  30. });
  31. const { message, ...result } = await response.json();
  32. if (response.ok) {
  33. return { state: ApiResulState.SUCCESS, message, user: result };
  34. } else {
  35. return {
  36. state: ApiResulState.ERROR,
  37. error: message.replace("Incorect", "Incorrect"),
  38. };
  39. }
  40. } catch (error) {
  41. return {
  42. state: ApiResulState.ERROR,
  43. error: `There was an error, please try again`,
  44. };
  45. }
  46. };
  47. export interface FetchApiInterface<T> {
  48. (body: T): Promise<FetchApiResult>;
  49. }
  50. export const login: FetchApiInterface<
  51. Pick<User, "email" | "password">
  52. > = async (body) => {
  53. const response = await fetchApi("/login", ApiMethods.POST, body);
  54. switch (response.state) {
  55. case ApiResulState.SUCCESS: {
  56. const user = await fetchUserData(body.email);
  57. return {
  58. ...response,
  59. user,
  60. };
  61. }
  62. default:
  63. return response;
  64. }
  65. };
  66. export const register: FetchApiInterface<
  67. Pick<User, "email" | "password">
  68. > = async (body) => {
  69. return fetchApi("/register", ApiMethods.POST, body);
  70. };
  71. export const updateUser: FetchApiInterface<
  72. Partial<User> & Pick<User, "id">
  73. > = async ({ id, ...body }) => {
  74. return fetchApi(`/user/${id}`, ApiMethods.PUT, body);
  75. };
  76. const fetchUsers = async (): Promise<Array<User>> => {
  77. const response = await fetch("/api/users");
  78. if (response.ok) {
  79. return response.json();
  80. } else {
  81. return Promise.resolve([]);
  82. }
  83. };
  84. const fetchUserData = async (email: string): Promise<User> => {
  85. const users = await fetchUsers();
  86. const user = users.find((user) => user.email === email);
  87. assert(user);
  88. return user;
  89. };
  90. const apiPaths = {
  91. login,
  92. register,
  93. updateUser,
  94. };
  95. export default apiPaths;