Skip to content

Commit

Permalink
Fix block range query parameter parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
0237h committed Sep 25, 2024
1 parent 9d9024b commit 4509e7b
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 125 deletions.
16 changes: 13 additions & 3 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { APP_VERSION } from "./src/config.js";
import { logger } from './src/logger.js';
import { makeUsageQuery } from "./src/usage.js";
import { APIErrorResponse } from "./src/utils.js";
import { usageOperationsToEndpointsMap, type EndpointReturnTypes, type UsageEndpoints, type ValidPathParams, type ValidUserParams } from "./src/types/api.js";
import { paths } from './src/types/zod.gen.js';
import { usageOperationsToEndpointsMap, ValidQueryParams, type EndpointReturnTypes, type UsageEndpoints, type ValidPathParams, type ValidUserParams } from "./src/types/api.js";
import { blockRangeSchema, paths } from './src/types/zod.gen.js';

async function AntelopeTokenAPI() {
const app = new Hono();
Expand Down Expand Up @@ -86,7 +86,17 @@ async function AntelopeTokenAPI() {
async (ctx: Context) => {
// Use `unknown` for undefined schemas definitions in `zod.gen.ts`
const path_params_schema = paths[endpoint]["get"]["parameters"]["path"] ?? z.unknown();
const query_params_schema = paths[endpoint]["get"]["parameters"]["query"] ?? z.unknown();
const query_params_schema = z.preprocess(
(q: any) => {
// Preprocess block ranges to array so Zod can parse it
if (q.block_range)
q.block_range = q.block_range.split(',');

return q;
},
paths[endpoint]["get"]["parameters"]["query"] ?? z.unknown()
);

const path_params = path_params_schema.safeParse(ctx.req.param());
const query_params = query_params_schema.safeParse(ctx.req.query());

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "antelope-token-api",
"description": "Token balances, supply and transfers from the Antelope blockchains",
"version": "6.0.0",
"version": "6.0.1",
"homepage": "https://github.com/pinax-network/antelope-token-api",
"license": "MIT",
"authors": [
Expand Down
44 changes: 24 additions & 20 deletions src/types/zod.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ export const apiErrorSchema = z.object({ "status": z.union([z.literal(500), z.li
export type ApiErrorSchema = z.infer<typeof apiErrorSchema>;


export const balanceSchema = z.object({ "last_updated_block": z.coerce.number(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "balance": z.coerce.number() });
export const balanceSchema = z.object({ "last_updated_block": z.coerce.number().int(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "balance": z.coerce.number() });
export type BalanceSchema = z.infer<typeof balanceSchema>;


export const balanceChangeSchema = z.object({ "trx_id": z.coerce.string(), "action_index": z.coerce.number(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "precision": z.coerce.number(), "amount": z.coerce.number(), "value": z.coerce.number(), "block_num": z.coerce.number(), "timestamp": z.coerce.string(), "account": z.coerce.string(), "balance": z.coerce.string(), "balance_delta": z.coerce.number() });
export const balanceChangeSchema = z.object({ "trx_id": z.coerce.string(), "action_index": z.coerce.number().int(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "precision": z.coerce.number().int(), "amount": z.coerce.number().int(), "value": z.coerce.number(), "block_num": z.coerce.number().int(), "timestamp": z.coerce.string(), "account": z.coerce.string(), "balance": z.coerce.string(), "balance_delta": z.coerce.number().int() });
export type BalanceChangeSchema = z.infer<typeof balanceChangeSchema>;


export const blockRangeSchema = z.array(z.coerce.number().int()).max(2);
export type BlockRangeSchema = z.infer<typeof blockRangeSchema>;


export const holderSchema = z.object({ "account": z.coerce.string(), "balance": z.coerce.number() });
export type HolderSchema = z.infer<typeof holderSchema>;

Expand All @@ -21,31 +25,31 @@ export const modelsScopeSchema = z.object({ "contract": z.coerce.string(), "symc
export type ModelsScopeSchema = z.infer<typeof modelsScopeSchema>;


export const paginationSchema = z.object({ "next_page": z.coerce.number(), "previous_page": z.coerce.number(), "total_pages": z.coerce.number(), "total_results": z.coerce.number() });
export const paginationSchema = z.object({ "next_page": z.coerce.number().int(), "previous_page": z.coerce.number().int(), "total_pages": z.coerce.number().int(), "total_results": z.coerce.number().int() });
export type PaginationSchema = z.infer<typeof paginationSchema>;


export const queryStatisticsSchema = z.object({ "elapsed": z.coerce.number(), "rows_read": z.coerce.number(), "bytes_read": z.coerce.number() });
export const queryStatisticsSchema = z.object({ "elapsed": z.coerce.number(), "rows_read": z.coerce.number().int(), "bytes_read": z.coerce.number().int() });
export type QueryStatisticsSchema = z.infer<typeof queryStatisticsSchema>;


export const responseMetadataSchema = z.object({ "statistics": z.lazy(() => queryStatisticsSchema).nullable(), "next_page": z.coerce.number(), "previous_page": z.coerce.number(), "total_pages": z.coerce.number(), "total_results": z.coerce.number() });
export const responseMetadataSchema = z.object({ "statistics": z.lazy(() => queryStatisticsSchema).nullable(), "next_page": z.coerce.number().int(), "previous_page": z.coerce.number().int(), "total_pages": z.coerce.number().int(), "total_results": z.coerce.number().int() });
export type ResponseMetadataSchema = z.infer<typeof responseMetadataSchema>;


export const supplySchema = z.object({ "trx_id": z.coerce.string(), "action_index": z.coerce.number(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "precision": z.coerce.number(), "amount": z.coerce.number(), "value": z.coerce.number(), "block_num": z.coerce.number(), "timestamp": z.coerce.string(), "issuer": z.coerce.string(), "max_supply": z.coerce.string(), "supply": z.coerce.string(), "supply_delta": z.coerce.number() });
export const supplySchema = z.object({ "trx_id": z.coerce.string(), "action_index": z.coerce.number().int(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "precision": z.coerce.number().int(), "amount": z.coerce.number().int(), "value": z.coerce.number(), "block_num": z.coerce.number().int(), "timestamp": z.coerce.string(), "issuer": z.coerce.string(), "max_supply": z.coerce.string(), "supply": z.coerce.string(), "supply_delta": z.coerce.number().int() });
export type SupplySchema = z.infer<typeof supplySchema>;


export const transferSchema = z.object({ "trx_id": z.coerce.string(), "action_index": z.coerce.number(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "precision": z.coerce.number(), "amount": z.coerce.number(), "value": z.coerce.number(), "block_num": z.coerce.number(), "timestamp": z.coerce.string(), "from": z.coerce.string(), "to": z.coerce.string(), "quantity": z.coerce.string(), "memo": z.coerce.string() });
export const transferSchema = z.object({ "trx_id": z.coerce.string(), "action_index": z.coerce.number().int(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "precision": z.coerce.number().int(), "amount": z.coerce.number().int(), "value": z.coerce.number(), "block_num": z.coerce.number().int(), "timestamp": z.coerce.string(), "from": z.coerce.string(), "to": z.coerce.string(), "quantity": z.coerce.string(), "memo": z.coerce.string() });
export type TransferSchema = z.infer<typeof transferSchema>;


export const versionSchema = z.object({ "version": z.coerce.string().regex(new RegExp("^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$")), "commit": z.coerce.string().regex(new RegExp("^[0-9a-f]{7}$")) });
export type VersionSchema = z.infer<typeof versionSchema>;


export const usageBalanceQueryParamsSchema = z.object({ "account": z.coerce.string(), "contract": z.coerce.string().optional(), "symcode": z.coerce.string().optional(), "limit": z.coerce.number().optional(), "page": z.coerce.number().optional() });
export const usageBalanceQueryParamsSchema = z.object({ "account": z.coerce.string(), "contract": z.coerce.string().optional(), "symcode": z.coerce.string().optional(), "limit": z.coerce.number().int().default(10).optional(), "page": z.coerce.number().int().default(1).optional() });
export type UsageBalanceQueryParamsSchema = z.infer<typeof usageBalanceQueryParamsSchema>;
/**
* @description Array of balances.
Expand All @@ -64,7 +68,7 @@ export const usageBalanceQueryResponseSchema = z.object({ "data": z.array(z.lazy
export type UsageBalanceQueryResponseSchema = z.infer<typeof usageBalanceQueryResponseSchema>;


export const usageBalanceHistoricalQueryParamsSchema = z.object({ "account": z.coerce.string(), "block_num": z.coerce.number(), "contract": z.coerce.string().optional(), "symcode": z.coerce.string().optional(), "limit": z.coerce.number().optional(), "page": z.coerce.number().optional() });
export const usageBalanceHistoricalQueryParamsSchema = z.object({ "account": z.coerce.string(), "block_num": z.coerce.number().int(), "contract": z.coerce.string().optional(), "symcode": z.coerce.string().optional(), "limit": z.coerce.number().int().default(10).optional(), "page": z.coerce.number().int().default(1).optional() });
export type UsageBalanceHistoricalQueryParamsSchema = z.infer<typeof usageBalanceHistoricalQueryParamsSchema>;
/**
* @description Array of balances.
Expand All @@ -83,12 +87,12 @@ export const usageBalanceHistoricalQueryResponseSchema = z.object({ "data": z.ar
export type UsageBalanceHistoricalQueryResponseSchema = z.infer<typeof usageBalanceHistoricalQueryResponseSchema>;


export const usageHeadQueryParamsSchema = z.object({ "limit": z.coerce.number().optional(), "page": z.coerce.number().optional() }).optional();
export const usageHeadQueryParamsSchema = z.object({ "limit": z.coerce.number().int().default(10).optional(), "page": z.coerce.number().int().default(1).optional() }).optional();
export type UsageHeadQueryParamsSchema = z.infer<typeof usageHeadQueryParamsSchema>;
/**
* @description Head block information.
*/
export const usageHead200Schema = z.object({ "data": z.array(z.object({ "block_num": z.coerce.number(), "block_id": z.coerce.string() })), "meta": z.lazy(() => responseMetadataSchema) });
export const usageHead200Schema = z.object({ "data": z.array(z.object({ "block_num": z.coerce.number().int(), "block_id": z.coerce.string() })), "meta": z.lazy(() => responseMetadataSchema) });
export type UsageHead200Schema = z.infer<typeof usageHead200Schema>;
/**
* @description An unexpected error response.
Expand All @@ -98,7 +102,7 @@ export type UsageHeadErrorSchema = z.infer<typeof usageHeadErrorSchema>;
/**
* @description Head block information.
*/
export const usageHeadQueryResponseSchema = z.object({ "data": z.array(z.object({ "block_num": z.coerce.number(), "block_id": z.coerce.string() })), "meta": z.lazy(() => responseMetadataSchema) });
export const usageHeadQueryResponseSchema = z.object({ "data": z.array(z.object({ "block_num": z.coerce.number().int(), "block_id": z.coerce.string() })), "meta": z.lazy(() => responseMetadataSchema) });
export type UsageHeadQueryResponseSchema = z.infer<typeof usageHeadQueryResponseSchema>;

/**
Expand All @@ -118,7 +122,7 @@ export const monitoringHealthQueryResponseSchema = z.coerce.string();
export type MonitoringHealthQueryResponseSchema = z.infer<typeof monitoringHealthQueryResponseSchema>;


export const usageHoldersQueryParamsSchema = z.object({ "contract": z.coerce.string(), "symcode": z.coerce.string(), "limit": z.coerce.number().optional(), "page": z.coerce.number().optional() });
export const usageHoldersQueryParamsSchema = z.object({ "contract": z.coerce.string(), "symcode": z.coerce.string(), "limit": z.coerce.number().int().default(10).optional(), "page": z.coerce.number().int().default(1).optional() });
export type UsageHoldersQueryParamsSchema = z.infer<typeof usageHoldersQueryParamsSchema>;
/**
* @description Array of accounts.
Expand Down Expand Up @@ -155,7 +159,7 @@ export type MonitoringMetricsQueryResponseSchema = z.infer<typeof monitoringMetr
/**
* @description The OpenAPI JSON spec
*/
export const docsOpenapi200Schema = z.object({});
export const docsOpenapi200Schema = z.object({}).catchall(z.any());
export type DocsOpenapi200Schema = z.infer<typeof docsOpenapi200Schema>;
/**
* @description An unexpected error response.
Expand All @@ -165,11 +169,11 @@ export type DocsOpenapiErrorSchema = z.infer<typeof docsOpenapiErrorSchema>;
/**
* @description The OpenAPI JSON spec
*/
export const docsOpenapiQueryResponseSchema = z.object({});
export const docsOpenapiQueryResponseSchema = z.object({}).catchall(z.any());
export type DocsOpenapiQueryResponseSchema = z.infer<typeof docsOpenapiQueryResponseSchema>;


export const usageSupplyQueryParamsSchema = z.object({ "block_num": z.coerce.number().optional(), "issuer": z.coerce.string().optional(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "limit": z.coerce.number().optional(), "page": z.coerce.number().optional() });
export const usageSupplyQueryParamsSchema = z.object({ "block_num": z.coerce.number().int().optional(), "issuer": z.coerce.string().optional(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "limit": z.coerce.number().int().default(10).optional(), "page": z.coerce.number().int().default(1).optional() });
export type UsageSupplyQueryParamsSchema = z.infer<typeof usageSupplyQueryParamsSchema>;
/**
* @description Array of supplies.
Expand All @@ -188,7 +192,7 @@ export const usageSupplyQueryResponseSchema = z.object({ "data": z.array(z.lazy(
export type UsageSupplyQueryResponseSchema = z.infer<typeof usageSupplyQueryResponseSchema>;


export const usageTokensQueryParamsSchema = z.object({ "limit": z.coerce.number().optional(), "page": z.coerce.number().optional() }).optional();
export const usageTokensQueryParamsSchema = z.object({ "limit": z.coerce.number().int().default(10).optional(), "page": z.coerce.number().int().default(1).optional() }).optional();
export type UsageTokensQueryParamsSchema = z.infer<typeof usageTokensQueryParamsSchema>;
/**
* @description Array of token identifier.
Expand All @@ -207,7 +211,7 @@ export const usageTokensQueryResponseSchema = z.object({ "data": z.array(z.lazy(
export type UsageTokensQueryResponseSchema = z.infer<typeof usageTokensQueryResponseSchema>;


export const usageTransfersQueryParamsSchema = z.object({ "block_range": z.array(z.coerce.number()).optional(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "limit": z.coerce.number().optional(), "page": z.coerce.number().optional() });
export const usageTransfersQueryParamsSchema = z.object({ "block_range": z.lazy(() => blockRangeSchema).optional(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "limit": z.coerce.number().int().default(10).optional(), "page": z.coerce.number().int().default(1).optional() });
export type UsageTransfersQueryParamsSchema = z.infer<typeof usageTransfersQueryParamsSchema>;
/**
* @description Array of transfers.
Expand All @@ -226,7 +230,7 @@ export const usageTransfersQueryResponseSchema = z.object({ "data": z.array(z.la
export type UsageTransfersQueryResponseSchema = z.infer<typeof usageTransfersQueryResponseSchema>;


export const usageTransfersAccountQueryParamsSchema = z.object({ "account": z.coerce.string(), "block_range": z.array(z.coerce.number()).optional(), "from": z.coerce.string().optional(), "to": z.coerce.string().optional(), "contract": z.coerce.string().optional(), "symcode": z.coerce.string().optional(), "limit": z.coerce.number().optional(), "page": z.coerce.number().optional() });
export const usageTransfersAccountQueryParamsSchema = z.object({ "account": z.coerce.string(), "block_range": z.lazy(() => blockRangeSchema).optional(), "from": z.coerce.string().optional(), "to": z.coerce.string().optional(), "contract": z.coerce.string().optional(), "symcode": z.coerce.string().optional(), "limit": z.coerce.number().int().default(10).optional(), "page": z.coerce.number().int().default(1).optional() });
export type UsageTransfersAccountQueryParamsSchema = z.infer<typeof usageTransfersAccountQueryParamsSchema>;
/**
* @description Array of transfers.
Expand All @@ -245,7 +249,7 @@ export const usageTransfersAccountQueryResponseSchema = z.object({ "data": z.arr
export type UsageTransfersAccountQueryResponseSchema = z.infer<typeof usageTransfersAccountQueryResponseSchema>;


export const usageTransferIdQueryParamsSchema = z.object({ "trx_id": z.coerce.string(), "limit": z.coerce.number().optional(), "page": z.coerce.number().optional() });
export const usageTransferIdQueryParamsSchema = z.object({ "trx_id": z.coerce.string(), "limit": z.coerce.number().int().default(10).optional(), "page": z.coerce.number().int().default(1).optional() });
export type UsageTransferIdQueryParamsSchema = z.infer<typeof usageTransferIdQueryParamsSchema>;
/**
* @description Array of transfers.
Expand Down
10 changes: 6 additions & 4 deletions src/typespec/openapi3.tsp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import "@typespec/http";
import "@typespec/openapi";
import "./models.tsp";
import "./config.js";

using TypeSpec.Http;
using TypeSpec.OpenAPI;
Expand All @@ -13,7 +12,7 @@ using TypeSpec.OpenAPI;
name: "MIT",
url: "https://github.com/pinax-network/antelope-token-api/blob/4f4bf36341b794c0ccf5b7a14fdf810be06462d2/LICENSE"
},
version: "6.0.0"
version: "6.0.1"
}) // From @typespec/openapi
//@server("https://eos.api.pinax.network/v1", "EOS V1 Api Endpoint")
namespace AntelopeTokenApi;
Expand Down Expand Up @@ -83,6 +82,9 @@ model UsageResponse<T> {
meta: ResponseMetadata;
}

@maxItems(2)
model BlockRange is BlockInfo.block_num[];

// Alias will *not* be present in the OpenAPI components.
// This also helps preventing self-references in generated `components` for codegen to work properly.
alias ApiResponse<T> = T | ApiError;
Expand Down Expand Up @@ -189,7 +191,7 @@ interface Usage {
@get
@useAuth(ApiKeyAuth<ApiKeyLocation.header, ApiKeyHeader>)
transfers(
@query({ format: "csv"}) block_range?: BlockInfo.block_num[],
@query(#{ explode: false }) block_range?: BlockRange,
@query contract: TokenIdentifier.contract,
@query symcode: TokenIdentifier.symcode,
...PaginationQueryParams,
Expand All @@ -205,7 +207,7 @@ interface Usage {
@useAuth(ApiKeyAuth<ApiKeyLocation.header, ApiKeyHeader>)
transfersAccount(
@query account: BalanceChange.account,
@query({ format: "csv"}) block_range?: BlockInfo.block_num[],
@query(#{ explode: false }) block_range?: BlockRange,
@query from?: Transfer.from,
@query to?: Transfer.to,
@query contract?: TokenIdentifier.contract,
Expand Down
2 changes: 1 addition & 1 deletion src/usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export async function makeUsageQuery(ctx: Context, endpoint: UsageEndpoints, use
let query = "";
let additional_query_params: AdditionalQueryParams = {};

// Parse block range for endpoints that uses it. Check for single value or two comma-separated values.
// Parse block range for endpoints that uses it. Check for single value or two values.
if (endpoint == "/transfers" || endpoint == "/transfers/account") {
const q = query_params as ValidUserParams<typeof endpoint>;
if (q.block_range) {
Expand Down
Loading

0 comments on commit 4509e7b

Please sign in to comment.