Skip to content

Commit

Permalink
chore: migrate axios to ky
Browse files Browse the repository at this point in the history
  • Loading branch information
rifandani committed Mar 18, 2024
1 parent e95dcd9 commit 1538cac
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 101 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
"@rifandani/nxact-yutiriti": "^1.2.2",
"@tanstack/react-query": "^5.28.4",
"@tanstack/react-query-devtools": "^5.28.4",
"axios": "^1.6.8",
"ky": "^1.2.2",
"react": "^18.2.0",
"react-aria": "^3.32.1",
"react-aria-components": "1.1.1",
Expand Down
66 changes: 12 additions & 54 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 18 additions & 9 deletions src/modules/auth/apis/auth.api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { ErrorApiResponseSchema } from '#shared/schemas/api.schema';
import { http } from '#shared/services/http.service';
import { z } from 'zod';

Expand Down Expand Up @@ -26,17 +25,27 @@ export const loginApiResponseSchema = z.object({

export const authApi = {
login: async (creds: LoginSchema) => {
const resp = await http.post<
LoginApiResponseSchema | ErrorApiResponseSchema
>('auth/login', creds);
const resp = await http
.post('auth/login', {
throwHttpErrors: false, // i'm expecting error response from the backend
json: creds,
hooks: {
afterResponse: [
async (request, _options, response) => {
if (response.status === 200) {
const data = (await response.json()) as LoginApiResponseSchema;
// set 'Authorization' headers
request.headers.set('Authorization', `Bearer ${data.token}`);
}
},
],
},
})
.json<LoginApiResponseSchema>();

// we also can use `parse` here. `parse` will throw if `resp.data` is not correct, and therefore can render `errorElement` if specified
// const loginApiResponse = loginApiResponseSchema.parse(resp.data);

// set 'Authorization' headers
if (resp.status === 200 && 'token' in resp.data)
http.defaults.headers.common.Authorization = `Bearer ${resp.data.token}`;

return resp.data;
return resp;
},
} as const;
14 changes: 12 additions & 2 deletions src/modules/auth/components/login-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ export function LoginForm() {
{/* username */}
<fieldset className="group/username form-control pt-4">
<label className="label" htmlFor="username">
<span className="label-text">{t('username')}</span>
<span
className="label-text aria-[invalid='true']:text-error"
aria-invalid={!!form.formState.errors.username?.message}
>
{t('username')}
</span>
</label>

<input
Expand All @@ -52,7 +57,12 @@ export function LoginForm() {
{/* password */}
<fieldset className="group/password form-control pt-4">
<label className="label" htmlFor="password">
<span className="label-text">{t('password')}</span>
<span
className="label-text aria-[invalid='true']:text-error"
aria-invalid={!!form.formState.errors.password?.message}
>
{t('password')}
</span>
</label>

<input
Expand Down
24 changes: 20 additions & 4 deletions src/modules/shared/configs/env.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
export const env = {
appTitle: import.meta.env.VITE_APP_TITLE ?? 'appTitle',
apiBaseUrl: import.meta.env.VITE_API_BASE_URL ?? 'apiBaseUrl',
} as const;
import { z } from 'zod';

export const envSchema = z.object({
VITE_APP_TITLE: z.string(),
VITE_API_BASE_URL: z.string().url(),
});

export const env = (() => {
const appTitle = envSchema.shape.VITE_APP_TITLE.parse(
import.meta.env.VITE_APP_TITLE,
);
const apiBaseUrl = envSchema.shape.VITE_API_BASE_URL.parse(
import.meta.env.VITE_API_BASE_URL,
);

return {
appTitle,
apiBaseUrl,
};
})();
12 changes: 6 additions & 6 deletions src/modules/shared/services/http.service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import axios from 'axios';
import { env } from '#shared/configs/env.config';
import ky from 'ky';

// Set config defaults when creating the instance
export const http = axios.create({
baseURL: env.apiBaseUrl,
validateStatus: (status) =>
// Resolve only if the status code is less than 500
status < 500,
export const http = ky.create({
prefixUrl: env.apiBaseUrl,
// validateStatus: status =>
// // Resolve only if the status code is less than 500
// status < 500,
});
51 changes: 26 additions & 25 deletions src/modules/todo/apis/todo.api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import type {
ErrorApiResponseSchema,
ResourceParamsSchema,
} from '#shared/schemas/api.schema';
import type { ResourceParamsSchema } from '#shared/schemas/api.schema';
import { resourceListSchema } from '#shared/schemas/api.schema';
import { http } from '#shared/services/http.service';
import { z } from 'zod';
Expand Down Expand Up @@ -66,39 +63,43 @@ export const todoKeys = {

export const todoApi = {
list: async (params: ResourceParamsSchema) => {
const resp = await http.get<
TodoListApiResponseSchema | ErrorApiResponseSchema
>('todos', { params });
const resp = await http
.get('todos', {
searchParams: params,
})
.json<TodoListApiResponseSchema>();

// `parse` will throw if `resp.data` is not correct, and therefore can render `errorElement` if specified
return todoListApiResponseSchema.parse(resp.data);
// we also can use `parse` here. `parse` will throw if `json` is not correct
// const response = todoListApiResponseSchema.parse(json);

return resp;
},
detail: async (id: TodoSchema['id']) => {
const resp = await http.get<
TodoDetailApiResponseSchema | ErrorApiResponseSchema
>(`todos/${id}`);
const resp = await http
.get(`todos/${id}`)
.json<TodoDetailApiResponseSchema>();

return todoDetailApiResponseSchema.parse(resp.data);
return resp;
},
create: async (todo: CreateTodoSchema) => {
const resp = await http.post<
CreateTodoApiResponseSchema | ErrorApiResponseSchema
>('todos/add', todo);
const resp = await http
.post('todos/add', { json: todo })
.json<CreateTodoApiResponseSchema>();

return createTodoApiResponseSchema.parse(resp.data);
return resp;
},
update: async ({ id, ...body }: UpdateTodoSchema) => {
const resp = await http.put<
UpdateTodoApiResponseSchema | ErrorApiResponseSchema
>(`todos/${id}`, body);
const resp = await http
.put(`todos/${id}`, { json: body })
.json<UpdateTodoApiResponseSchema>();

return updateTodoApiResponseSchema.parse(resp.data);
return resp;
},
delete: async (id: TodoSchema['id']) => {
const resp = await http.delete<
DeleteTodoApiResponseSchema | ErrorApiResponseSchema
>(`todos/${id}`);
const resp = await http
.delete(`todos/${id}`)
.json<DeleteTodoApiResponseSchema>();

return deleteTodoApiResponseSchema.parse(resp.data);
return resp;
},
} as const;

0 comments on commit 1538cac

Please sign in to comment.