Gathering detailed insights and metrics for @api-ts/io-ts-http
Gathering detailed insights and metrics for @api-ts/io-ts-http
Gathering detailed insights and metrics for @api-ts/io-ts-http
Gathering detailed insights and metrics for @api-ts/io-ts-http
npm install @api-ts/io-ts-http
Typescript
Module System
Node Version
NPM Version
98.9
Supply Chain
98
Quality
84.1
Maintenance
100
Vulnerability
100
License
Verify real, reachable, and deliverable emails with instant MX records, SMTP checks, and disposable email detection.
Total Downloads
15,286,239
Last Day
13,750
Last Week
69,123
Last Month
356,601
Last Year
12,466,124
Latest Version
3.2.1
Package Id
@api-ts/io-ts-http@3.2.1
Unpacked Size
60.94 kB
Size
15.34 kB
File Count
31
NPM Version
10.5.2
Node Version
20.17.0
Published on
Sep 13, 2024
Cumulative downloads
Total Downloads
Last Day
-16.7%
13,750
Compared to previous day
Last Week
-8.5%
69,123
Compared to previous week
Last Month
-50.3%
356,601
Compared to previous month
Last Year
459.3%
12,466,124
Compared to previous year
4
3
Runtime types for (de)serializing HTTP requests from both the client and server side
This package extends io-ts with functionality useful for typing HTTP requests. Start there for base knowledge required to use this package.
io-ts-http is the definition language for api-ts specifications, which define the API contract for a web sever to an arbitrary degree of precision. Web servers can use the io-ts-http spec to parse HTTP requests at runtime, and encode HTTP responses. Clients can use the io-ts-http spec to enforce API compatibility at compile time, and to encode requests to the server and decode responses.
The primary function in this library is httpRequest
. You can use this to build codecs
which can parse a generic HTTP request into a more refined type. The generic HTTP
request should conform to the following interface:
1interface GenericHttpRequest { 2 params: { 3 [K: string]: string; 4 }; 5 query: { 6 [K: string]: string | string[]; 7 }; 8 headers: { 9 [K: string]: string; 10 }; 11 body?: unknown; 12}
Here, params
represents the path parameters and query
is minimally-parsed query
string parameters (basically just the results of splitting up the query string and
urlDecoding the values). The httpRequest
function can be combined with codecs from
io-ts
to build a combined codec that is able to validate, parse, and encode these
generic HTTP requests into a more refined object. For example:
1import { httpRequest, optional } from '@api-ts/io-ts-http'; 2import { DateFromISOString, NumberFromString } from 'io-ts-types'; 3 4const ExampleHttpRequest = httpRequest({ 5 query: { 6 id: NumberFromString, 7 time: optional(DateFromISOString), 8 }, 9});
This builds a codec that can be given an arbitrary HTTP request and will ensure that it
contains an id
parameter, and also optionally will check for a time
parameter, and
if it is present, validate and parse it to a Date
. If decoding succeeds, then the
resulting value's type will be:
1type ExampleDecodedResult = { 2 id: number; 3 time?: Date; 4};
This type is properly inferred by TypeScript and can be used in destructuring like so:
1import { pipe } from 'fp-ts/function'; 2import * as E from 'fp-ts/Either'; 3 4const { id, time } = pipe( 5 ExampleHttpRequest.decode(request), 6 E.getOrElseW((decodeErrors) => { 7 someErrorHandler(decodeErrors); 8 }), 9);
to get request argument validation and parsing as a one-liner. These codecs can also be used from the client-side to get the type safety around making outgoing requests. An API client could hypothetically have a method like:
1apiClient.request(route, ExampleHttpRequest, { 2 id: 1337, 3 time: new Date(), 4});
If both the server and client use the same codec for the request, then it becomes possible to encode the API contract (or at least as much of it that is possible to express in the type system) and therefore someone calling the API can be confident that the server will correctly interpret a request if the arguments typecheck.
Let's define the api-ts spec for a hypothetical message-user
service. The conventional
top-level export is an
apiSpec
value; for example:
apiSpec
1import { apiSpec } from '@api-ts/io-ts-http'; 2 3import { GetMessage, CreateMessage } from './routes/message'; 4import { GetUser, CreateUser, PatchUser, UpdateUser, DeleteUser } from './routes/user'; 5 6/** 7 * message-user service 8 * 9 * @version 1.0.0 10 */ 11export const API = apiSpec({ 12 'api.v1.message': { 13 get: GetMessage, 14 post: CreateMessage, 15 }, 16 'api.v1.user': { 17 get: GetUser, 18 post: CreateUser, 19 put: UpdateUser, 20 delete: DeleteUser, 21 patch: PatchUser, 22 }, 23});
The apiSpec
is imported, along with some named httpRoute
s ({Get|Create}Message
,
and {Get|Create|Update|Delete}User
) which we'll discuss below.
Currently, if you add the
@version
JSDoc tag to the exported API spec, it will be used as the APIversion
when generating an OpenAPI schema. Support for other tags may be added in the future.
The top-level export for message-user-types
is API
, which we define as an apiSpec
with two endpoints api/v1/message
and api/v1/user
. The api/v1/message
endpoint
responds to GET
and POST
verbs while the second reponds to GET
, POST
, PUT
, and
DELETE
verbs using httpRoute
s defined in ./routes/message
. The following are the
httpRoute
s defined in ./routes/message
.
httpRoute
1import * as t from 'io-ts'; 2import { httpRoute, httpRequest } from '@api-ts/io-ts-http'; 3 4export const GetMessage = httpRoute({ 5 path: '/message/{id}', 6 method: 'GET', 7 request: httpRequest({ 8 params: { 9 id: t.string, 10 }, 11 }), 12 response: { 13 200: t.type({ 14 id: t.string, 15 message: t.string, 16 }), 17 404: t.type({ 18 error: t.string, 19 }), 20 }, 21}); 22 23export const CreateMessage = httpRoute({ 24 path: '/message', 25 method: 'POST', 26 request: httpRequest({ 27 body: { 28 message: t.string, 29 }, 30 }), 31 response: { 32 200: t.type({ 33 id: t.string, 34 message: t.string, 35 }), 36 404: t.type({ 37 error: t.string, 38 }), 39 }, 40});
The first import is the io-ts
package. It's usually imported as t
for use in
describing the types of data properties. Again, review
io-ts documentation for more context on how to use it
and this package.
Then httpRoute
and httpRequest
are imported. We'll review the
httpRequest
below, but first, let's review the GetMessage
httpRoute
.
1export const GetMessage = httpRoute({ 2 path: '/message/{id}', 3 method: 'GET', 4 request: httpRequest({ 5 params: { 6 id: t.string, 7 }, 8 }), 9 response: { 10 200: t.type({ 11 id: t.string, 12 message: t.string, 13 }), 14 404: t.type({ 15 error: t.string, 16 }), 17 }, 18});
httpRoute
s
apiSpec
s use
httpRoute
s
to define the path
, method
, request
and response
of a route.
path
The route's path
along with possible path variables. You should surround variables
with brackets like {name}
, and are to the request
codec under the params
property.
method
The route's method
is the
HTTP request method to use
for that route. In our GetMessage
example, the method
is GET
, while in our
PostMessage
example, the method
is POST
.
request
The route's request
is the output of the httpRequest
function. This will be
described below.
response
The route's response
describes the possible
HTTP responses the route can
produce. The key-value pairs of the response
object are an HTTP status code followed
by the io-ts
type of the response body. In our GetMessage
example, a 200
status
response yields a payload of a JSON object with two properties, message
which is a
string
and id
which is also a string
, and a 404
yeilds a payload of a JSON
object with a single property error
which is a String
.
httpRequest
Use httpRequest
to build the expected type that you pass in a request to the route. In
our example GetMessage
1export const GetMessage = httpRoute({ 2 path: '/message/{id}', 3 method: 'GET', 4 request: httpRequest({ 5 params: { 6 id: t.string, 7 }, 8 }), 9 // ... 10});
httpRequest
s have a total of 4 optional properties: params
(shown in the example),
query
, headers
, and body
.
params
params
is an object representing the types of path parameters in a URL. Any URL
parameters in the path
property of an httpRoute
must be accounted for in the
params
property of the httpRequest
. Our request has a single URL parameter it is
expecting, id
. This is the type of this parameter is captured in the params
object
of our httpRequest
.
query
query
is the object representing the values passed in via query parameters at the end
of a URL. The following example uses a new route, GetMessages
, to our API that
searches messages related to a specific author
:
1export const GetMessages = httpRoute({ 2 path: '/messages', 3 method: 'GET', 4 request: httpRequest({ 5 query: { 6 author: t.string, 7 }, 8 }), 9 // ... 10});
headers
headers
is an object representing the types of the
HTTP headers passed in with
a request.
body
body
is an object representing the type of the
HTTP body of a
request. Often this is a JSON object. The CreateMessage
httpRoute
in our example
uses the body
property:
1export const CreateMessage = httpRoute({ 2 path: '/message', 3 method: 'POST', 4 request: httpRequest({ 5 body: { 6 message: t.string, 7 }, 8 }), 9 // ... 10});
httpRequest
When you decode httpRequests
using io-ts
helpers, the properties of the request are
flattened like this:
1import { DateFromISOString, NumberFromString } from 'io-ts-types'; 2 3// build an httpRequest with one parameter id and a body with content and a timestamp 4const Request = httpRequest({ 5 params: { 6 id: NumberFromString, 7 }, 8 body: { 9 content: t.string, 10 timestamp: DateFromISOString, 11 }, 12}); 13 14// use io-ts to get the type of the Request 15type Request = t.TypeOf<typeof Request>; 16 17// same as 18type Request = { 19 id: number; 20 content: string; 21 timestamp: Date; 22};
No vulnerabilities found.
No security vulnerabilities found.
@api-ts/openapi-generator
Generate an OpenAPI specification from an io-ts-http contract
@ty-ras/frontend-fetch-io-ts
Bundle of TyRAS libraries suitable to use in frontends/clients which use Fetch API to send HTTP requests, and `io-ts` as data validation library.
typed-http-api
TypeScript type system compliant communication via HTTP.
@hishprorg/assumenda-tempora-eius
Node [streams2](http://nodejs.org/api/stream.html) over [Primus](https://github.com/primus/primus): added back-pressure!