express-zod-api
Advanced tools
Changelog
v2.3.0
ZodArray: # z.array()
before:
type: array
items:
type: type # type of the array items
after:
type: array
items:
type: type
minItems: value # optional, when z.array().min(value)
maxItems: value # optional, when z.array().max(value)
ZodTuple: # z.tuple()
before:
error: unsupported
after:
type: array
items:
oneOf: [] # schemas of the tuple items
minItems: value # number of items in the tuple
maxItems: value # number of items in the tuple
description: "0: type, 1: type, etc"
Changelog
v2.2.0
ZodBigInt: # z.bigint()
before:
type: integer
format: int64
after:
type: integer
format: bigint
ZodNumber: # z.number()
before:
type: number
after:
type: number | integer # when z.number().int()
format: double | int64 # when z.number().int()
# MIN_VALUE or MIN_SAFE_INTEGER of Number or z.number().min(value)
minimum: 5e-324 | -9007199254740991 | value
# MAX_VALUE or MAX_SAFE_INTEGER of Number or z.number().max(value)
maximum: 1.7976931348623157e+308 | 9007199254740991 | value
# Taking into account z.number().min(), .max(), .positive(), .nonnegative(), etc
exclusiveMinimum: true | false
exclusiveMaximum: true | false
ZodString: # z.string()
before:
type: string
after:
type: string
minLength: value # optional, when z.string().min(value)
maxLength: value # optional, when z.string().max(value)
format: email | uuid | url # when z.string().email(), .uuid(), .url()
pattern: /your regular expression/ # when z.string().regex(value)
z.number().int()
is a
JS Number which is
neither int32
nor int64
but rather int53
, I made a decision to describe it as int64
predefined format
with
an indispensable minimum and maximum values.Changelog
v2.1.0
ZodFile
can be created using z.file()
. It has two refinements: .binary()
and
.base64()
which also reflected in the generated Swagger / OpenAPI documentation.
You can use it instead of z.string()
with createApiResponse()
:// before
const fileStreamingEndpointsFactoryBefore = new EndpointsFactory(
createResultHandler({
getPositiveResponse: () => createApiResponse(z.string(), "image/*"),
// ...,
}),
);
// after
const fileStreamingEndpointsFactoryAfter = new EndpointsFactory(
createResultHandler({
getPositiveResponse: () => createApiResponse(z.file().binary(), "image/*"),
// ...,
}),
);
z.file()
within the Endpoint
input / output object schemas.Changelog
v2.0.0
defaultResultHandler
before, then you won't have to change much of code.ResultHandler
is responsible. So I decided to fix it, although it made the implementation somewhat more
complicated, but I found it important. However, it brought a number of benefits, which are also described below.10.0.0
and the library target now is ES6
.ResultHandler
is no longer exported, please use createResultHandler()
or defaultResultHandler
.resultHandler
of ConfigType
has been replaced with errorHandler
.setResultHandler()
method of EndpointsFactory
class has been removed. The ResultHandlerDefinition
has
to be specified as an argument of EndpointsFactory
constructor. You can use defaultResultHandler
or
createResultHandler()
for this, or you can use defaultEndpointsFactory
.Endpoint
class getPositiveResponseSchema()
and getNegativeResponseSchema()
return the
complete response of the endpoint taking into account the ResultHandlerDefinition
schemas.
New methods: getPositiveMimeTypes()
and getNegativeMimeTypes()
return the array of mime types.EndpointResponse<E extends AbstractEndpoint>
to be used instead of EndpointOutput
returns the complete type of the endpoint response including both positive and negative cases.EndpointOutput<>
type helper for the non-object response type in the ResultHandlerDefinition
.ResultHandler
and a file download.getSpecAsYaml()
method
directly on OpenAPI
class instance. There is also a new option errorResponseDescription
.getPositiveMimeTypes()
and getNegativeMimeTypes()
usage in Swagger docs generator.default
entry in responses
there are HTTP status codes 200
and 400
that represent positive
and negative responses accordingly. Response schemas are now complete as well.ResultHandlerDefinition
please use createResultHandler()
. It also requires
createApiResponse()
to be used that takes a response schema and optional mime types as arguments.
The endpoint output should be wrapped in markOutput()
. So far this is the only way I have come up with to
facilitate type inference with essentially double nesting of generic types. Typescript does not yet support such
features as MyGenericType<A<B>>
.// before
export const endpointsFactoryBefore = new EndpointsFactory();
// after
export const endpointsFactoryAfter = new EndpointsFactory(defaultResultHandler);
// which is the same as
import { defaultEndpointsFactory } from "express-zod-api";
// before
resultHandler: ResultHandler; // optional
// after
errorHandler: ResultHandlerDefinition<any, any>; // optional, default: defaultResultHandler
// Example. Before (v1):
import { EndpointOutput } from "express-zod-api";
const myEndpointV1 = endpointsFactory.build({
method: "get",
input: z.object({
/* ... */
}),
output: z.object({
name: z.string(),
}),
handler: async () => ({
/* ... */
}),
});
type MyEndpointOutput = EndpointOutput<typeof myEndpointV1>; // => { name: string }
// and after (v2):
import { defaultEndpointsFactory, EndpointResponse } from "express-zod-api";
const myEndpointV2 = defaultEndpointsFactory.build({
method: "get",
input: z.object({
/* ... */
}),
output: z.object({
name: z.string(),
}),
handler: async () => ({
/* ... */
}),
});
type MyEndpointResponse = EndpointResponse<typeof myEndpointV2>; // => the following type:
// {
// status: 'success';
// data: { name: string };
// } | {
// status: 'error',
// error: { message: string };
// }
// before
new OpenAPI({
/* ... */
}).builder.getSpecAsYaml();
// after
new OpenAPI({
/* ... */
}).getSpecAsYaml();
// before
const myResultHandlerV1: ResultHandler = ({
error,
request,
response,
input,
output,
logger,
}) => {
/* ... */
};
// after
const myResultHandlerV2 = createResultHandler({
getPositiveResponse: <OUT extends IOSchema>(output: OUT) =>
createApiResponse(
z.object({
// ...,
someProperty: markOutput(output),
}),
["mime/type1", "mime/type2"], // optional, default: application/json
),
getNegativeResponse: () =>
createApiResponse(
z.object({
/* ... */
}),
),
handler: ({ error, input, output, request, response, logger }) => {
/* ... */
},
});
Changelog
v1.3.1
cors: true
the OPTIONS requests have not been handled properly.
This was leading to the 404 error with a message "Can not OPTIONS <route>".
The issue has been fixed and covered by multiple tests.