Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix block range query parameter parsing #76

Merged
merged 2 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Hono, type Context } from "hono";
import { type RootResolver, graphqlServer, getGraphQLParams } from '@hono/graphql-server';
import { type RootResolver, graphqlServer } from '@hono/graphql-server';
import { buildSchema } from 'graphql';
import { SafeParseSuccess, z } from 'zod';

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
48 changes: 25 additions & 23 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,21 +159,19 @@ export type MonitoringMetricsQueryResponseSchema = z.infer<typeof monitoringMetr
/**
* @description The OpenAPI JSON spec
*/
export const docsOpenapi200Schema = z.object({});
export const docsOpenapi200Schema = z.any();
export type DocsOpenapi200Schema = z.infer<typeof docsOpenapi200Schema>;
/**
* @description An unexpected error response.
*/
export const docsOpenapiErrorSchema = z.lazy(() => apiErrorSchema);
export type DocsOpenapiErrorSchema = z.infer<typeof docsOpenapiErrorSchema>;
/**
* @description The OpenAPI JSON spec
*/
export const docsOpenapiQueryResponseSchema = z.object({});

export const docsOpenapiQueryResponseSchema = 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 +190,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 +209,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 +228,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 +247,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
12 changes: 7 additions & 5 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 Expand Up @@ -244,7 +246,7 @@ interface Docs {
@summary("OpenAPI JSON spec")
@route("/openapi")
@get
openapi(): ApiResponse<Record<unknown>>;
openapi(): ApiResponse<{}>;

/**
Api version and Git short commit hash.
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
12 changes: 0 additions & 12 deletions static/@openapi-to-graphql/graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,6 @@ type Query {
"""
metrics: String

"""
Reflection endpoint to return OpenAPI JSON spec. Also used by Swagger to generate the frontpage.

Equivalent to GET /openapi
"""
openapi: JSON

"""
Total supply for a token.

Expand Down Expand Up @@ -162,11 +155,6 @@ type Holder {
balance: Float!
}

"""
The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).
"""
scalar JSON @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf")

type Supply {
data: [Supply2]!
meta: ResponseMetadata!
Expand Down
Loading
Loading