diff --git a/apps/ensapi/src/handlers/ensnode-api.routes.ts b/apps/ensapi/src/handlers/ensnode-api.routes.ts new file mode 100644 index 000000000..be00913b6 --- /dev/null +++ b/apps/ensapi/src/handlers/ensnode-api.routes.ts @@ -0,0 +1,55 @@ +import { createRoute } from "@hono/zod-openapi"; + +import { + makeEnsApiIndexingStatusResponseErrorSchema, + makeSerializedEnsApiIndexingStatusResponseOkSchema, + makeSerializedEnsApiPublicConfigSchema, +} from "@ensnode/ensnode-sdk/internal"; + +export const basePath = "/api"; + +export const getConfigRoute = createRoute({ + method: "get", + path: "/config", + tags: ["Meta"], + summary: "Get ENSApi Public Config", + description: "Gets the public config of the ENSApi instance", + responses: { + 200: { + description: "Successfully retrieved ENSApi public config", + content: { + "application/json": { + schema: makeSerializedEnsApiPublicConfigSchema(), + }, + }, + }, + }, +}); + +export const getIndexingStatusRoute = createRoute({ + method: "get", + path: "/indexing-status", + tags: ["Meta"], + summary: "Get ENSIndexer Indexing Status", + description: "Returns the indexing status snapshot most recently captured from ENSIndexer", + responses: { + 200: { + description: "Successfully retrieved indexing status", + content: { + "application/json": { + schema: makeSerializedEnsApiIndexingStatusResponseOkSchema(), + }, + }, + }, + 503: { + description: "Indexing status snapshot unavailable", + content: { + "application/json": { + schema: makeEnsApiIndexingStatusResponseErrorSchema(), + }, + }, + }, + }, +}); + +export const routes = [getConfigRoute, getIndexingStatusRoute]; diff --git a/apps/ensapi/src/handlers/ensnode-api.ts b/apps/ensapi/src/handlers/ensnode-api.ts index 46d458dad..96e65d0c9 100644 --- a/apps/ensapi/src/handlers/ensnode-api.ts +++ b/apps/ensapi/src/handlers/ensnode-api.ts @@ -1,101 +1,53 @@ import config from "@/config"; -import { describeRoute, resolver as validationResolver } from "hono-openapi"; - import { - IndexingStatusResponseCodes, - type IndexingStatusResponseError, - type IndexingStatusResponseOk, + EnsApiIndexingStatusResponseCodes, + type EnsApiIndexingStatusResponseError, + type EnsApiIndexingStatusResponseOk, serializeENSApiPublicConfig, - serializeIndexingStatusResponse, + serializeEnsApiIndexingStatusResponse, } from "@ensnode/ensnode-sdk"; -import { - makeENSApiPublicConfigSchema, - makeIndexingStatusResponseSchema, -} from "@ensnode/ensnode-sdk/internal"; import { buildEnsApiPublicConfig } from "@/config/config.schema"; -import { factory } from "@/lib/hono-factory"; +import { createApp } from "@/lib/hono-factory"; +import { getConfigRoute, getIndexingStatusRoute } from "./ensnode-api.routes"; import ensnodeGraphQLApi from "./ensnode-graphql-api"; import nameTokensApi from "./name-tokens-api"; import registrarActionsApi from "./registrar-actions-api"; import resolutionApi from "./resolution-api"; -const app = factory.createApp(); +const app = createApp(); -app.get( - "/config", - describeRoute({ - tags: ["Meta"], - summary: "Get ENSApi Public Config", - description: "Gets the public config of the ENSApi instance", - responses: { - 200: { - description: "Successfully retrieved ENSApi public config", - content: { - "application/json": { - schema: validationResolver(makeENSApiPublicConfigSchema()), - }, - }, - }, - }, - }), - async (c) => { - const ensApiPublicConfig = buildEnsApiPublicConfig(config); - return c.json(serializeENSApiPublicConfig(ensApiPublicConfig)); - }, -); +app.openapi(getConfigRoute, async (c) => { + const ensApiPublicConfig = buildEnsApiPublicConfig(config); + return c.json(serializeENSApiPublicConfig(ensApiPublicConfig)); +}); -app.get( - "/indexing-status", - describeRoute({ - tags: ["Meta"], - summary: "Get ENSIndexer Indexing Status", - description: "Returns the indexing status snapshot most recently captured from ENSIndexer", - responses: { - 200: { - description: "Successfully retrieved indexing status", - content: { - "application/json": { - schema: validationResolver(makeIndexingStatusResponseSchema()), - }, - }, - }, - 503: { - description: "Indexing status snapshot unavailable", - content: { - "application/json": { - schema: validationResolver(makeIndexingStatusResponseSchema()), - }, - }, - }, - }, - }), - async (c) => { - // context must be set by the required middleware - if (c.var.indexingStatus === undefined) { - throw new Error(`Invariant(indexing-status): indexingStatusMiddleware required`); - } +app.openapi(getIndexingStatusRoute, async (c) => { + // context must be set by the required middleware + if (c.var.indexingStatus === undefined) { + throw new Error(`Invariant(indexing-status): indexingStatusMiddleware required`); + } - if (c.var.indexingStatus instanceof Error) { - return c.json( - serializeIndexingStatusResponse({ - responseCode: IndexingStatusResponseCodes.Error, - } satisfies IndexingStatusResponseError), - 503, - ); - } - - // return successful response using the indexing status projection from the middleware context + if (c.var.indexingStatus instanceof Error) { return c.json( - serializeIndexingStatusResponse({ - responseCode: IndexingStatusResponseCodes.Ok, - realtimeProjection: c.var.indexingStatus, - } satisfies IndexingStatusResponseOk), + serializeEnsApiIndexingStatusResponse({ + responseCode: EnsApiIndexingStatusResponseCodes.Error, + } satisfies EnsApiIndexingStatusResponseError), + 503, ); - }, -); + } + + // return successful response using the indexing status projection from the middleware context + return c.json( + serializeEnsApiIndexingStatusResponse({ + responseCode: EnsApiIndexingStatusResponseCodes.Ok, + realtimeProjection: c.var.indexingStatus, + } satisfies EnsApiIndexingStatusResponseOk), + 200, + ); +}); // Name Tokens API app.route("/name-tokens", nameTokensApi); diff --git a/apps/ensapi/src/stub-routes.ts b/apps/ensapi/src/stub-routes.ts index 3a36ddf32..73a0372a9 100644 --- a/apps/ensapi/src/stub-routes.ts +++ b/apps/ensapi/src/stub-routes.ts @@ -1,6 +1,7 @@ import { OpenAPIHono } from "@hono/zod-openapi"; import * as amIRealtimeRoutes from "./handlers/amirealtime-api.routes"; +import * as ensnodeRoutes from "./handlers/ensnode-api.routes"; import * as resolutionRoutes from "./handlers/resolution-api.routes"; /** @@ -11,7 +12,7 @@ import * as resolutionRoutes from "./handlers/resolution-api.routes"; export function createStubRoutesForSpec() { const app = new OpenAPIHono(); - const routeGroups = [amIRealtimeRoutes, resolutionRoutes]; + const routeGroups = [amIRealtimeRoutes, ensnodeRoutes, resolutionRoutes]; for (const group of routeGroups) { for (const route of group.routes) { diff --git a/packages/ensnode-sdk/src/ensapi/api/indexing-status/serialize.ts b/packages/ensnode-sdk/src/ensapi/api/indexing-status/serialize.ts index 9cc13d5d6..5dcf85b87 100644 --- a/packages/ensnode-sdk/src/ensapi/api/indexing-status/serialize.ts +++ b/packages/ensnode-sdk/src/ensapi/api/indexing-status/serialize.ts @@ -1,13 +1,28 @@ import { serializeRealtimeIndexingStatusProjection } from "../../../indexing-status/serialize/realtime-indexing-status-projection"; -import { type EnsApiIndexingStatusResponse, EnsApiIndexingStatusResponseCodes } from "./response"; +import { + type EnsApiIndexingStatusResponse, + EnsApiIndexingStatusResponseCodes, + type EnsApiIndexingStatusResponseError, + type EnsApiIndexingStatusResponseOk, +} from "./response"; import type { SerializedEnsApiIndexingStatusResponse, + SerializedEnsApiIndexingStatusResponseError, SerializedEnsApiIndexingStatusResponseOk, } from "./serialized-response"; /** * Serialize a {@link EnsApiIndexingStatusResponse} object. */ +export function serializeEnsApiIndexingStatusResponse( + response: EnsApiIndexingStatusResponseOk, +): SerializedEnsApiIndexingStatusResponseOk; +export function serializeEnsApiIndexingStatusResponse( + response: EnsApiIndexingStatusResponseError, +): SerializedEnsApiIndexingStatusResponseError; +export function serializeEnsApiIndexingStatusResponse( + response: EnsApiIndexingStatusResponse, +): SerializedEnsApiIndexingStatusResponse; export function serializeEnsApiIndexingStatusResponse( response: EnsApiIndexingStatusResponse, ): SerializedEnsApiIndexingStatusResponse {