Comparing version 0.0.5-rc-20230306144928-649819c to 0.0.5-rc-20230306145011-afaf5fc
{ | ||
"name": "fets", | ||
"version": "0.0.5-rc-20230306144928-649819c", | ||
"version": "0.0.5-rc-20230306145011-afaf5fc", | ||
"description": "TypeScript HTTP Framework focusing on e2e type-safety, easy setup, performance & great developer experience", | ||
@@ -5,0 +5,0 @@ "sideEffects": false, |
252
README.md
@@ -38,9 +38,9 @@ # FETS | ||
FETS also doesn't need a code generation like tRPC doesn't, but FETS also allows you to export an OpenAPI | ||
document based on the JSON Schema definitions if you don't want to share TypeScript definitions | ||
between the client and the server. tRPC uses a programmatic solution like `zod` but FETS uses a more | ||
popular alternative [JSON Schema](https://json-schema.org/) which is more portable and completely | ||
language agnostic. If you want to have a similar experience like `zod` instead of writing JSON | ||
Schemas manually with objects, you can use `@sinclair/typebox` to generate them by using an API like | ||
`zod` has. | ||
FETS also doesn't need a code generation like tRPC doesn't, but FETS also allows you to export an | ||
OpenAPI document based on the JSON Schema definitions if you don't want to share TypeScript | ||
definitions between the client and the server. tRPC uses a programmatic solution like `zod` but FETS | ||
uses a more popular alternative [JSON Schema](https://json-schema.org/) which is more portable and | ||
completely language agnostic. If you want to have a similar experience like `zod` instead of writing | ||
JSON Schemas manually with objects, you can use `@sinclair/typebox` to generate them by using an API | ||
like `zod` has. | ||
[See how to use typebox with FETS.](#using-a-programmatic-json-schema-builder-zod-like-api) | ||
@@ -198,3 +198,3 @@ | ||
} | ||
}); | ||
}) | ||
``` | ||
@@ -369,28 +369,26 @@ | ||
const router = createRouter().route( | ||
{ | ||
method: 'post', | ||
path: '/todos', | ||
// Define the request body schema | ||
schemas: { | ||
request: { | ||
json: { | ||
type: 'object', | ||
properties: { | ||
title: { type: 'string' }, | ||
completed: { type: 'boolean' } | ||
}, | ||
additionalProperties: false, | ||
required: ['title'] | ||
} | ||
const router = createRouter().route({ | ||
method: 'post', | ||
path: '/todos', | ||
// Define the request body schema | ||
schemas: { | ||
request: { | ||
json: { | ||
type: 'object', | ||
properties: { | ||
title: { type: 'string' }, | ||
completed: { type: 'boolean' } | ||
}, | ||
additionalProperties: false, | ||
required: ['title'] | ||
} | ||
} as const, | ||
handler: async request => { | ||
// This part is fully typed | ||
const { title, completed } = await request.json() | ||
// ... | ||
return Response.json({ message: 'ok' }) | ||
} | ||
}, | ||
) | ||
} as const, | ||
handler: async request => { | ||
// This part is fully typed | ||
const { title, completed } = await request.json() | ||
// ... | ||
return Response.json({ message: 'ok' }) | ||
} | ||
}) | ||
``` | ||
@@ -403,29 +401,27 @@ | ||
const router = createRouter().route( | ||
{ | ||
method: 'post', | ||
path: '/todos', | ||
// Define the request body schema | ||
schemas: { | ||
request: { | ||
headers: { | ||
type: 'object', | ||
properties: { | ||
'x-api-key': { type: 'string' } | ||
}, | ||
additionalProperties: false, | ||
required: ['x-api-key'] | ||
} | ||
const router = createRouter().route({ | ||
method: 'post', | ||
path: '/todos', | ||
// Define the request body schema | ||
schemas: { | ||
request: { | ||
headers: { | ||
type: 'object', | ||
properties: { | ||
'x-api-key': { type: 'string' } | ||
}, | ||
additionalProperties: false, | ||
required: ['x-api-key'] | ||
} | ||
} as const, | ||
handler: async request => { | ||
// This part is fully typed | ||
const apiKey = request.headers.get('x-api-key') | ||
// Would fail on TypeScript compilation | ||
const wrongHeaderName = request.headers.get('x-api-key-wrong') | ||
// ... | ||
return Response.json({ message: 'ok' }) | ||
} | ||
}, | ||
) | ||
} as const, | ||
handler: async request => { | ||
// This part is fully typed | ||
const apiKey = request.headers.get('x-api-key') | ||
// Would fail on TypeScript compilation | ||
const wrongHeaderName = request.headers.get('x-api-key-wrong') | ||
// ... | ||
return Response.json({ message: 'ok' }) | ||
} | ||
}) | ||
``` | ||
@@ -438,27 +434,25 @@ | ||
const router = createRouter().route( | ||
{ | ||
method: 'get', | ||
path: '/todos/:id', | ||
// Define the request body schema | ||
schemas: { | ||
request: { | ||
params: { | ||
type: 'object', | ||
properties: { | ||
id: { type: 'string' } | ||
}, | ||
additionalProperties: false, | ||
required: ['id'] | ||
} | ||
const router = createRouter().route({ | ||
method: 'get', | ||
path: '/todos/:id', | ||
// Define the request body schema | ||
schemas: { | ||
request: { | ||
params: { | ||
type: 'object', | ||
properties: { | ||
id: { type: 'string' } | ||
}, | ||
additionalProperties: false, | ||
required: ['id'] | ||
} | ||
} as const, | ||
handler: async request => { | ||
// This part is fully typed | ||
const { id } = request.params | ||
// ... | ||
return Response.json({ message: 'ok' }) | ||
} | ||
}, | ||
) | ||
} as const, | ||
handler: async request => { | ||
// This part is fully typed | ||
const { id } = request.params | ||
// ... | ||
return Response.json({ message: 'ok' }) | ||
} | ||
}) | ||
``` | ||
@@ -507,62 +501,60 @@ | ||
const router = createRouter().addRoute( | ||
{ | ||
method: 'get', | ||
path: '/todos', | ||
// Define the request body schema | ||
schemas: { | ||
request: { | ||
headers: { | ||
const router = createRouter().addRoute({ | ||
method: 'get', | ||
path: '/todos', | ||
// Define the request body schema | ||
schemas: { | ||
request: { | ||
headers: { | ||
type: 'object', | ||
properties: { | ||
'x-api-key': { type: 'string' } | ||
}, | ||
additionalProperties: false, | ||
required: ['x-api-key'] | ||
} | ||
}, | ||
responses: { | ||
200: { | ||
type: 'array', | ||
items: { | ||
type: 'object', | ||
properties: { | ||
'x-api-key': { type: 'string' } | ||
id: { type: 'string' }, | ||
title: { type: 'string' }, | ||
completed: { type: 'boolean' } | ||
}, | ||
additionalProperties: false, | ||
required: ['x-api-key'] | ||
required: ['id', 'title', 'completed'] | ||
} | ||
}, | ||
responses: { | ||
200: { | ||
type: 'array', | ||
items: { | ||
type: 'object', | ||
properties: { | ||
id: { type: 'string' }, | ||
title: { type: 'string' }, | ||
completed: { type: 'boolean' } | ||
}, | ||
additionalProperties: false, | ||
required: ['id', 'title', 'completed'] | ||
} | ||
401: { | ||
type: 'object', | ||
properties: { | ||
message: { type: 'string' } | ||
}, | ||
401: { | ||
type: 'object', | ||
properties: { | ||
message: { type: 'string' } | ||
}, | ||
additionalProperties: false, | ||
required: ['message'] | ||
} | ||
additionalProperties: false, | ||
required: ['message'] | ||
} | ||
} as const, | ||
handler: async request => { | ||
const apiKey = request.headers.get('x-api-key') | ||
if (!apiKey) { | ||
return Response.json( | ||
{ message: 'API key is required' }, | ||
{ | ||
status: 401 | ||
} | ||
) | ||
} | ||
const todos = await getTodos({ | ||
apiKey | ||
}) | ||
// This part is fully typed | ||
return Response.json(todos, { | ||
status: 200 | ||
}) | ||
} | ||
} as const, | ||
handler: async request => { | ||
const apiKey = request.headers.get('x-api-key') | ||
if (!apiKey) { | ||
return Response.json( | ||
{ message: 'API key is required' }, | ||
{ | ||
status: 401 | ||
} | ||
) | ||
} | ||
const todos = await getTodos({ | ||
apiKey | ||
}) | ||
// This part is fully typed | ||
return Response.json(todos, { | ||
status: 200 | ||
}) | ||
} | ||
) | ||
}) | ||
``` | ||
@@ -569,0 +561,0 @@ |
100298
726