Ross Gerbasi
01/10/2022, 2:14 AMImportant Compiling schemas on the fly will cause a 50-100ms performance hit during cold start for simple JSON Schemas. Precompiling is highly recommended.
I really would rather not get into a build step to pre-compile json schemas but also not interested in taking a 50-100ms performance hit.
My latest experiment is using io-ts
which I cant find many benchmarks on, just this one, https://github.com/gcanti/io-ts-benchmarks. I updated these with 2 new tests(io-ts-init
and ajv-setup
. I just exported a function instead of the cached type. So each test has to call the function first to get the validator. I also tested this with just in-lining the io-ts
code right into the test (no calling a function) and the results are almost identical. So no major overhead in the function call.
As you can see AJV sucks when you need to call setup over and over, though io-ts
loses a lot also like 5x slower 😕 .
Anyway curious what others have tried, failed, succeeded?Garret Harp
01/10/2022, 2:28 AMRoss Gerbasi
01/10/2022, 2:55 AMRoss Gerbasi
01/10/2022, 4:22 AMajv
way behind for this situation, definitely optimized for create once situations.
Looking like io-ts
with is
is the best bet right now. Can check that and if its not valid can call decode to get an error, which is hopefully less likely. Though most of these are so far sub MS its probably fair to go either way.
forked repo here. https://github.com/aphex/io-ts-benchmarks
I am going the path of adding this to my body-parser
util with io-ts
for now.Ross Gerbasi
01/10/2022, 4:23 AMAdam Fanello
01/10/2022, 4:20 PMthdxr
01/10/2022, 5:29 PMthdxr
01/10/2022, 5:30 PMRoss Gerbasi
01/10/2022, 5:50 PMexport type IOTSType = t.TypeOf<ReturnType<typeof getType>>
So now IOTSType will just be the type for an object following your schema. This also plays very nicely with io-ts's is
method as it works as a type guard. if (<http://MyType.is|MyType.is>(body))
then body is of type MyType
. To make this easier we name our schema and our types the same.
const MyType = t.type({...}
and
export type MyType = t.TypeOf<typeof MyType>
Not totally sold on whether this makes things more or less confusing yet 🙂 but with import
and import type
we can get to these even if we need to. However generally we done export the schema, just the type.
From what I can tell the Type info is totally stripped away by esbuild so this has no effect on performance.Adam Fanello
01/10/2022, 5:56 PMinterface
definition of my types, with JsDoc describing things as needed. I think what I want is to hand write OpenAPI, and have it generate Typescript interfaces and validation functions.Ross Gerbasi
01/10/2022, 5:58 PMAdam Fanello
01/10/2022, 6:00 PMRoss Gerbasi
01/10/2022, 6:00 PMRoss Gerbasi
01/10/2022, 6:00 PMRoss Gerbasi
01/10/2022, 6:02 PMRoss Gerbasi
01/10/2022, 6:14 PMio-ts
code from your OpenAPI, this could be a very welcome pacakge for the community that is interested in running spec change scripts.
So you would write the openapi and generate once, it would create a io-ts schema, TS types and inherently a validator for each type. Again this is a step you need to run anytime you change the spec, but I think that's what you're going for.Ross Gerbasi
01/10/2022, 6:15 PMRoss Gerbasi
01/10/2022, 6:17 PMAdam Fanello
01/10/2022, 6:18 PMRoss Gerbasi
01/10/2022, 6:18 PMAdam Fanello
01/10/2022, 6:19 PMAdam Fanello
01/11/2022, 1:12 AMRoss Gerbasi
01/11/2022, 1:13 AMAdam Fanello
01/11/2022, 1:17 AMRoss Gerbasi
01/11/2022, 1:17 AMRoss Gerbasi
01/11/2022, 1:18 AMopenapi: 3.0.0
info:
title: My Schema
version: 1.0.0
paths:
/test/thing:
post:
operationId: test
description: test
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
id:
type: string
name:
type: string
required:
- id
- name
responses:
'200':
description: Same Stuff.
content:
application/json:
schema:
type: object
properties:
id:
type: string
name:
type: string
components: {}
tags: []
Ross Gerbasi
01/11/2022, 1:18 AMimport { ApiError, ApiResponse, HttpRequestAdapter, Operation, request } from "@openapi-io-ts/runtime";
import { TaskEither } from "fp-ts/TaskEither";
import * as t from "io-ts";
export const TestRequestBodySchema = t.type({
id: t.string,
name: t.string
})
export interface TestRequestBodySchema {
id: string,
name: string
}
export const TestResponse200Schema = t.partial({
id: t.string,
name: t.string
})
export interface TestResponse200Schema {
id?: string,
name?: string
}
export const testOperation: Operation = {
path: "/test/thing",
method: "post",
responses: { "200": { _tag: "JsonResponse", decoder: TestResponse200Schema } },
parameters: [],
requestDefaultHeaders: { "Content-Type": "application/json", "Accept": "application/json" },
body: {
_tag: "JsonBody"
}
}
export const testBuilder = (requestAdapter: HttpRequestAdapter) => (body: TestRequestBodySchema): TaskEither<ApiError, ApiResponse<TestResponse200Schema>> =>
request(testOperation, {}, body, requestAdapter);
Adam Fanello
01/11/2022, 1:20 AMRoss Gerbasi
01/11/2022, 1:22 AMAdam Fanello
01/11/2022, 1:23 AMRoss Gerbasi
01/11/2022, 1:23 AMRoss Gerbasi
01/11/2022, 1:23 AMAdam Fanello
01/11/2022, 1:23 AMAdam Fanello
01/11/2022, 1:23 AMRoss Gerbasi
01/11/2022, 1:24 AMRoss Gerbasi
01/11/2022, 1:24 AMRoss Gerbasi
01/11/2022, 1:25 AMAdam Fanello
01/11/2022, 1:30 AMAdam Fanello
01/11/2022, 1:37 AMAdam Fanello
01/12/2022, 4:41 PMNote: At the moment the only OpenAPI version supported isÂ. If you have aÂ3.0
 file you have to convert it toÂ2.0
 before. VersionÂ3.0
 is not supported at the moment.3.1