feat: migrate from Elysia Eden to Contract-First API (OpenAPI)
This commit is contained in:
@@ -45,6 +45,23 @@ export const apikey = new Elysia({
|
||||
}
|
||||
},
|
||||
{
|
||||
response: {
|
||||
200: t.Object({
|
||||
apiKeys: t.Array(
|
||||
t.Object({
|
||||
id: t.String(),
|
||||
name: t.String(),
|
||||
key: t.String(),
|
||||
isActive: t.Boolean(),
|
||||
expiresAt: t.Union([t.String(), t.Null(), t.Any()]),
|
||||
createdAt: t.Any(),
|
||||
updatedAt: t.Any(),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
401: t.Object({ error: t.String() }),
|
||||
500: t.Object({ error: t.String() }),
|
||||
},
|
||||
detail: {
|
||||
summary: "Get all API keys",
|
||||
description: "Get all API keys",
|
||||
@@ -97,6 +114,21 @@ export const apikey = new Elysia({
|
||||
name: t.String(),
|
||||
expiresAt: t.Optional(t.String()), // ISO date string
|
||||
}),
|
||||
response: {
|
||||
200: t.Object({
|
||||
apiKey: t.Object({
|
||||
id: t.String(),
|
||||
name: t.String(),
|
||||
key: t.String(),
|
||||
isActive: t.Boolean(),
|
||||
expiresAt: t.Union([t.String(), t.Null(), t.Any()]),
|
||||
createdAt: t.Any(),
|
||||
updatedAt: t.Any(),
|
||||
}),
|
||||
}),
|
||||
401: t.Object({ error: t.String() }),
|
||||
500: t.Object({ error: t.String() }),
|
||||
},
|
||||
detail: {
|
||||
summary: "Create a new API key",
|
||||
description: "Create a new API key",
|
||||
@@ -174,6 +206,22 @@ export const apikey = new Elysia({
|
||||
isActive: t.Boolean(),
|
||||
expiresAt: t.Optional(t.Union([t.String(), t.Null()])), // ISO date string or null
|
||||
}),
|
||||
response: {
|
||||
200: t.Object({
|
||||
apiKey: t.Object({
|
||||
id: t.String(),
|
||||
name: t.String(),
|
||||
key: t.String(),
|
||||
isActive: t.Boolean(),
|
||||
expiresAt: t.Union([t.String(), t.Null(), t.Any()]),
|
||||
createdAt: t.Any(),
|
||||
updatedAt: t.Any(),
|
||||
}),
|
||||
}),
|
||||
401: t.Object({ error: t.String() }),
|
||||
403: t.Object({ error: t.String() }),
|
||||
500: t.Object({ error: t.String() }),
|
||||
},
|
||||
detail: {
|
||||
summary: "Update an API key",
|
||||
description: "Update an API key",
|
||||
@@ -225,6 +273,14 @@ export const apikey = new Elysia({
|
||||
body: t.Object({
|
||||
id: t.String(),
|
||||
}),
|
||||
response: {
|
||||
200: t.Object({
|
||||
success: t.Boolean(),
|
||||
}),
|
||||
500: t.Object({ error: t.String() }),
|
||||
403: t.Object({ error: t.String() }),
|
||||
401: t.Object({ error: t.String() }),
|
||||
},
|
||||
detail: {
|
||||
summary: "Delete an API key",
|
||||
description: "Delete an API key",
|
||||
|
||||
@@ -86,6 +86,11 @@ export function apiMiddleware(app: Elysia) {
|
||||
}
|
||||
})
|
||||
.onBeforeHandle(({ user, set, request }) => {
|
||||
const url = new URL(request.url);
|
||||
if (url.pathname.startsWith("/api/docs")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
logger.warn(`[AUTH] Unauthorized: ${request.method} ${request.url}`);
|
||||
set.status = 401;
|
||||
|
||||
@@ -68,9 +68,12 @@ function DashboardApikeyComponent() {
|
||||
const fetchApiKeys = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await apiClient.api.apikey.get();
|
||||
if (response.data) {
|
||||
setApiKeys((response.data.apiKeys as any) || []);
|
||||
const { data, error } = await apiClient.GET("/api/apikey/");
|
||||
if (data) {
|
||||
setApiKeys((data.apiKeys as any) || []);
|
||||
}
|
||||
if (error) {
|
||||
setError("Failed to load API keys");
|
||||
}
|
||||
} catch (err) {
|
||||
setError("Failed to load API keys");
|
||||
@@ -92,19 +95,24 @@ function DashboardApikeyComponent() {
|
||||
|
||||
try {
|
||||
setCreating(true);
|
||||
const response = await apiClient.api.apikey.post({
|
||||
name: newKeyName,
|
||||
expiresAt: newKeyExpiresAt
|
||||
? dayjs(newKeyExpiresAt).toISOString()
|
||||
: undefined,
|
||||
const { data, error } = await apiClient.POST("/api/apikey/", {
|
||||
body: {
|
||||
name: newKeyName,
|
||||
expiresAt: newKeyExpiresAt
|
||||
? dayjs(newKeyExpiresAt).toISOString()
|
||||
: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
if (response.data) {
|
||||
setApiKeys([...apiKeys, response.data.apiKey as any]);
|
||||
if (data) {
|
||||
setApiKeys([...apiKeys, data.apiKey as any]);
|
||||
setNewKeyName("");
|
||||
setNewKeyExpiresAt(null);
|
||||
setCreateModalOpen(false);
|
||||
}
|
||||
if (error) {
|
||||
setError("Failed to create API key");
|
||||
}
|
||||
} catch (err) {
|
||||
setError("Failed to create API key");
|
||||
console.error(err);
|
||||
@@ -119,18 +127,23 @@ function DashboardApikeyComponent() {
|
||||
setError("API key ID is required");
|
||||
return;
|
||||
}
|
||||
const response = await apiClient.api.apikey.update.post({
|
||||
id,
|
||||
isActive: !currentStatus,
|
||||
const { data, error } = await apiClient.POST("/api/apikey/update", {
|
||||
body: {
|
||||
id,
|
||||
isActive: !currentStatus,
|
||||
},
|
||||
});
|
||||
|
||||
if (response.data) {
|
||||
if (data) {
|
||||
setApiKeys(
|
||||
apiKeys.map((key) =>
|
||||
key.id === id ? { ...key, isActive: !currentStatus } : key,
|
||||
),
|
||||
);
|
||||
}
|
||||
if (error) {
|
||||
setError("Failed to update API key status");
|
||||
}
|
||||
} catch (err) {
|
||||
setError("Failed to update API key status");
|
||||
console.error(err);
|
||||
@@ -147,12 +160,18 @@ function DashboardApikeyComponent() {
|
||||
if (!keyToDelete) return;
|
||||
|
||||
try {
|
||||
await apiClient.api.apikey.delete.post({
|
||||
id: keyToDelete,
|
||||
const { error } = await apiClient.POST("/api/apikey/delete", {
|
||||
body: {
|
||||
id: keyToDelete,
|
||||
},
|
||||
});
|
||||
setApiKeys(apiKeys.filter((key: ApiKey) => key.id !== keyToDelete));
|
||||
setDeleteModalOpen(false);
|
||||
setKeyToDelete(null);
|
||||
if (!error) {
|
||||
setApiKeys(apiKeys.filter((key: ApiKey) => key.id !== keyToDelete));
|
||||
setDeleteModalOpen(false);
|
||||
setKeyToDelete(null);
|
||||
} else {
|
||||
setError("Failed to delete API key");
|
||||
}
|
||||
} catch (err) {
|
||||
setError("Failed to delete API key");
|
||||
console.error(err);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { edenTreaty } from "@elysiajs/eden";
|
||||
import type { ApiApp } from "../index";
|
||||
import createClient from "openapi-fetch";
|
||||
import type { paths } from "../../generated/api";
|
||||
import { VITE_PUBLIC_URL } from "./env";
|
||||
|
||||
const baseUrl =
|
||||
@@ -8,4 +8,7 @@ const baseUrl =
|
||||
? window.location.origin
|
||||
: "http://localhost:3000");
|
||||
|
||||
export const apiClient = edenTreaty<ApiApp>(baseUrl);
|
||||
export const apiClient = createClient<paths>({
|
||||
baseUrl: baseUrl,
|
||||
credentials: "include",
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user