adorn-api 1.0.23 → 1.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +3 -0
- package/.eslintrc.cjs +30 -0
- package/README.md +375 -531
- package/dist/core/express-adapter.d.ts +27 -0
- package/dist/core/express-adapter.d.ts.map +1 -0
- package/dist/core/express-adapter.js +146 -0
- package/dist/core/express-adapter.js.map +1 -0
- package/dist/core/http-error.d.ts +7 -0
- package/dist/core/http-error.d.ts.map +1 -0
- package/dist/core/http-error.js +14 -0
- package/dist/core/http-error.js.map +1 -0
- package/dist/decorators/controller.decorator.d.ts +2 -0
- package/dist/decorators/controller.decorator.d.ts.map +1 -0
- package/dist/decorators/controller.decorator.js +26 -0
- package/dist/decorators/controller.decorator.js.map +1 -0
- package/dist/decorators/create.decorator.d.ts +8 -0
- package/dist/decorators/create.decorator.d.ts.map +1 -0
- package/dist/decorators/create.decorator.js +67 -0
- package/dist/decorators/create.decorator.js.map +1 -0
- package/dist/decorators/http-method.decorator.d.ts +16 -0
- package/dist/decorators/http-method.decorator.d.ts.map +1 -0
- package/dist/decorators/http-method.decorator.js +117 -0
- package/dist/decorators/http-method.decorator.js.map +1 -0
- package/dist/decorators/http-params.d.ts +17 -0
- package/dist/decorators/http-params.d.ts.map +1 -0
- package/dist/decorators/http-params.js +26 -0
- package/dist/decorators/http-params.js.map +1 -0
- package/dist/decorators/index.d.ts +10 -5
- package/dist/decorators/index.d.ts.map +1 -1
- package/dist/decorators/index.js +14 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/decorators/list.decorator.d.ts +18 -0
- package/dist/decorators/list.decorator.d.ts.map +1 -0
- package/dist/decorators/list.decorator.js +99 -0
- package/dist/decorators/list.decorator.js.map +1 -0
- package/dist/decorators/middleware.decorator.d.ts +4 -0
- package/dist/decorators/middleware.decorator.d.ts.map +1 -0
- package/dist/decorators/middleware.decorator.js +34 -0
- package/dist/decorators/middleware.decorator.js.map +1 -0
- package/dist/decorators/response.decorator.d.ts +8 -0
- package/dist/decorators/response.decorator.d.ts.map +1 -0
- package/dist/decorators/response.decorator.js +44 -0
- package/dist/decorators/response.decorator.js.map +1 -0
- package/dist/decorators/route-options.d.ts +14 -0
- package/dist/decorators/route-options.d.ts.map +1 -0
- package/dist/decorators/route-options.js +22 -0
- package/dist/decorators/route-options.js.map +1 -0
- package/dist/decorators/schema.decorator.d.ts +82 -0
- package/dist/decorators/schema.decorator.d.ts.map +1 -0
- package/dist/decorators/schema.decorator.js +123 -0
- package/dist/decorators/schema.decorator.js.map +1 -0
- package/dist/decorators/update.decorator.d.ts +8 -0
- package/dist/decorators/update.decorator.d.ts.map +1 -0
- package/dist/decorators/update.decorator.js +63 -0
- package/dist/decorators/update.decorator.js.map +1 -0
- package/dist/index.d.ts +11 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -637
- package/dist/index.js.map +1 -1
- package/dist/metadata/metadata-storage.d.ts +38 -0
- package/dist/metadata/metadata-storage.d.ts.map +1 -0
- package/dist/metadata/metadata-storage.js +102 -0
- package/dist/metadata/metadata-storage.js.map +1 -0
- package/dist/metal-orm-integration/dto-helper.d.ts +5 -0
- package/dist/metal-orm-integration/dto-helper.d.ts.map +1 -0
- package/dist/metal-orm-integration/dto-helper.js +48 -0
- package/dist/metal-orm-integration/dto-helper.js.map +1 -0
- package/dist/metal-orm-integration/dto-response.decorator.d.ts +4 -0
- package/dist/metal-orm-integration/dto-response.decorator.d.ts.map +1 -0
- package/dist/metal-orm-integration/dto-response.decorator.js +69 -0
- package/dist/metal-orm-integration/dto-response.decorator.js.map +1 -0
- package/dist/metal-orm-integration/entity-schema-builder.d.ts +20 -0
- package/dist/metal-orm-integration/entity-schema-builder.d.ts.map +1 -0
- package/dist/metal-orm-integration/entity-schema-builder.js +356 -0
- package/dist/metal-orm-integration/entity-schema-builder.js.map +1 -0
- package/dist/metal-orm-integration/index.d.ts +5 -0
- package/dist/metal-orm-integration/index.d.ts.map +1 -0
- package/dist/metal-orm-integration/index.js +5 -0
- package/dist/metal-orm-integration/index.js.map +1 -0
- package/dist/metal-orm-integration/schema-modifier.d.ts +11 -0
- package/dist/metal-orm-integration/schema-modifier.d.ts.map +1 -0
- package/dist/metal-orm-integration/schema-modifier.js +62 -0
- package/dist/metal-orm-integration/schema-modifier.js.map +1 -0
- package/dist/openapi/index.d.ts +4 -0
- package/dist/openapi/index.d.ts.map +1 -0
- package/dist/openapi/index.js +4 -0
- package/dist/openapi/index.js.map +1 -0
- package/dist/openapi/openapi-generator.d.ts +22 -0
- package/dist/openapi/openapi-generator.d.ts.map +1 -0
- package/dist/openapi/openapi-generator.js +428 -0
- package/dist/openapi/openapi-generator.js.map +1 -0
- package/dist/openapi/swagger-ui.d.ts +11 -0
- package/dist/openapi/swagger-ui.d.ts.map +1 -0
- package/dist/openapi/swagger-ui.js +20 -0
- package/dist/openapi/swagger-ui.js.map +1 -0
- package/dist/openapi/zod-to-openapi.d.ts +4 -0
- package/dist/openapi/zod-to-openapi.d.ts.map +1 -0
- package/dist/openapi/zod-to-openapi.js +184 -0
- package/dist/openapi/zod-to-openapi.js.map +1 -0
- package/dist/types/common.d.ts +4 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +2 -0
- package/dist/types/common.js.map +1 -0
- package/dist/types/controller.d.ts +14 -0
- package/dist/types/controller.d.ts.map +1 -0
- package/dist/types/controller.js +2 -0
- package/dist/types/controller.js.map +1 -0
- package/dist/types/metadata.d.ts +48 -0
- package/dist/types/metadata.d.ts.map +1 -0
- package/dist/types/metadata.js +2 -0
- package/dist/types/metadata.js.map +1 -0
- package/dist/types/openapi.d.ts +30 -0
- package/dist/types/openapi.d.ts.map +1 -0
- package/dist/types/openapi.js +2 -0
- package/dist/types/openapi.js.map +1 -0
- package/dist/validation/zod-adapter.d.ts +15 -0
- package/dist/validation/zod-adapter.d.ts.map +1 -0
- package/dist/validation/zod-adapter.js +61 -0
- package/dist/validation/zod-adapter.js.map +1 -0
- package/examples/basic/app.ts +15 -0
- package/examples/basic/index.ts +6 -0
- package/examples/basic/user.controller.ts +35 -0
- package/examples/basic/user.dtos.ts +23 -0
- package/examples/metal-orm-sqlite/app.ts +18 -0
- package/examples/metal-orm-sqlite/db.ts +90 -0
- package/examples/metal-orm-sqlite/index.ts +6 -0
- package/examples/metal-orm-sqlite/post.controller.ts +209 -0
- package/examples/metal-orm-sqlite/post.dtos.ts +78 -0
- package/examples/metal-orm-sqlite/post.entity.ts +24 -0
- package/examples/metal-orm-sqlite/user.controller.helpers.ts +305 -0
- package/examples/metal-orm-sqlite/user.controller.ts +231 -0
- package/examples/metal-orm-sqlite/user.dtos.ts +88 -0
- package/examples/metal-orm-sqlite/user.entity.ts +21 -0
- package/examples/metal-orm-sqlite-music/album.controller.ts +278 -0
- package/examples/metal-orm-sqlite-music/album.dtos.ts +85 -0
- package/examples/metal-orm-sqlite-music/album.entity.ts +28 -0
- package/examples/metal-orm-sqlite-music/app.ts +19 -0
- package/examples/metal-orm-sqlite-music/artist.controller.ts +272 -0
- package/examples/metal-orm-sqlite-music/artist.dtos.ts +68 -0
- package/examples/metal-orm-sqlite-music/artist.entity.ts +27 -0
- package/examples/metal-orm-sqlite-music/db.ts +148 -0
- package/examples/metal-orm-sqlite-music/index.ts +6 -0
- package/examples/metal-orm-sqlite-music/track.controller.ts +221 -0
- package/examples/metal-orm-sqlite-music/track.dtos.ts +82 -0
- package/examples/metal-orm-sqlite-music/track.entity.ts +27 -0
- package/examples/openapi/health.controller.ts +11 -0
- package/examples/openapi/health.dto.ts +7 -0
- package/examples/openapi/index.ts +12 -0
- package/examples/restful/app.ts +15 -0
- package/examples/restful/index.ts +9 -0
- package/examples/restful/task.controller.ts +118 -0
- package/examples/restful/task.dtos.ts +66 -0
- package/examples/restful/task.store.ts +95 -0
- package/examples/tsconfig.json +8 -0
- package/examples/utils/start-server.ts +56 -0
- package/package.json +33 -97
- package/scripts/run-example.js +29 -0
- package/src/adapter/express.ts +589 -0
- package/src/adapter/metal-orm/convention-overrides.ts +115 -0
- package/src/adapter/metal-orm/crud-dtos.ts +141 -0
- package/src/adapter/metal-orm/dto.ts +20 -0
- package/src/adapter/metal-orm/error-dtos.ts +51 -0
- package/src/adapter/metal-orm/field-builder.ts +185 -0
- package/src/adapter/metal-orm/filters.ts +52 -0
- package/src/adapter/metal-orm/index.ts +66 -0
- package/src/adapter/metal-orm/paged-dtos.ts +94 -0
- package/src/adapter/metal-orm/pagination.ts +28 -0
- package/src/adapter/metal-orm/types.ts +250 -0
- package/src/adapter/metal-orm/utils.ts +36 -0
- package/src/adapter/metal-orm.test.ts +439 -0
- package/src/core/__tests__/coerce.test.ts +39 -0
- package/src/core/__tests__/dto-compose.test.ts +68 -0
- package/src/core/__tests__/schema-builder.test.ts +82 -0
- package/src/core/coerce.ts +190 -0
- package/src/core/decorators.ts +645 -0
- package/src/core/errors.ts +55 -0
- package/src/core/metadata.ts +110 -0
- package/src/core/openapi.ts +282 -0
- package/src/core/schema-builder.ts +287 -0
- package/src/core/schema.ts +400 -0
- package/src/core/types.ts +14 -0
- package/src/e2e/http-error.e2e.test.ts +52 -0
- package/src/e2e/sqlite-metal-orm.e2e.test.ts +174 -0
- package/src/e2e/sqlite.e2e.test.ts +126 -0
- package/src/index.ts +8 -0
- package/tsconfig.eslint.json +7 -0
- package/tsconfig.json +18 -0
- package/vitest.config.ts +8 -0
- package/dist/adapter/express/auth.d.ts +0 -13
- package/dist/adapter/express/auth.d.ts.map +0 -1
- package/dist/adapter/express/bootstrap.d.ts +0 -40
- package/dist/adapter/express/bootstrap.d.ts.map +0 -1
- package/dist/adapter/express/coercion.d.ts +0 -102
- package/dist/adapter/express/coercion.d.ts.map +0 -1
- package/dist/adapter/express/index.d.ts +0 -6
- package/dist/adapter/express/index.d.ts.map +0 -1
- package/dist/adapter/express/merge.d.ts +0 -45
- package/dist/adapter/express/merge.d.ts.map +0 -1
- package/dist/adapter/express/openapi.d.ts +0 -66
- package/dist/adapter/express/openapi.d.ts.map +0 -1
- package/dist/adapter/express/router.d.ts +0 -10
- package/dist/adapter/express/router.d.ts.map +0 -1
- package/dist/adapter/express/swagger.d.ts +0 -18
- package/dist/adapter/express/swagger.d.ts.map +0 -1
- package/dist/adapter/express/types.d.ts +0 -110
- package/dist/adapter/express/types.d.ts.map +0 -1
- package/dist/adapter/express/validation.d.ts +0 -27
- package/dist/adapter/express/validation.d.ts.map +0 -1
- package/dist/cli/progress.d.ts +0 -124
- package/dist/cli/progress.d.ts.map +0 -1
- package/dist/cli.cjs +0 -4622
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -4603
- package/dist/cli.js.map +0 -1
- package/dist/compiler/analyze/index.d.ts +0 -5
- package/dist/compiler/analyze/index.d.ts.map +0 -1
- package/dist/compiler/analyze/scanControllers.d.ts +0 -88
- package/dist/compiler/analyze/scanControllers.d.ts.map +0 -1
- package/dist/compiler/cache/isStale.d.ts +0 -46
- package/dist/compiler/cache/isStale.d.ts.map +0 -1
- package/dist/compiler/cache/loadArtifacts.d.ts +0 -149
- package/dist/compiler/cache/loadArtifacts.d.ts.map +0 -1
- package/dist/compiler/cache/schema.d.ts +0 -32
- package/dist/compiler/cache/schema.d.ts.map +0 -1
- package/dist/compiler/cache/writeCache.d.ts +0 -14
- package/dist/compiler/cache/writeCache.d.ts.map +0 -1
- package/dist/compiler/gems.d.ts +0 -75
- package/dist/compiler/gems.d.ts.map +0 -1
- package/dist/compiler/generator/index.d.ts +0 -7
- package/dist/compiler/generator/index.d.ts.map +0 -1
- package/dist/compiler/generator/manifest.d.ts +0 -23
- package/dist/compiler/generator/manifest.d.ts.map +0 -1
- package/dist/compiler/generator/openapi.d.ts +0 -118
- package/dist/compiler/generator/openapi.d.ts.map +0 -1
- package/dist/compiler/graph/builder.d.ts +0 -24
- package/dist/compiler/graph/builder.d.ts.map +0 -1
- package/dist/compiler/graph/index.d.ts +0 -7
- package/dist/compiler/graph/index.d.ts.map +0 -1
- package/dist/compiler/graph/schemaGraph.d.ts +0 -67
- package/dist/compiler/graph/schemaGraph.d.ts.map +0 -1
- package/dist/compiler/graph/types.d.ts +0 -203
- package/dist/compiler/graph/types.d.ts.map +0 -1
- package/dist/compiler/index.d.ts +0 -12
- package/dist/compiler/index.d.ts.map +0 -1
- package/dist/compiler/ir/index.d.ts +0 -7
- package/dist/compiler/ir/index.d.ts.map +0 -1
- package/dist/compiler/ir/pipeline.d.ts +0 -82
- package/dist/compiler/ir/pipeline.d.ts.map +0 -1
- package/dist/compiler/ir/stages.d.ts +0 -40
- package/dist/compiler/ir/stages.d.ts.map +0 -1
- package/dist/compiler/ir/visitor.d.ts +0 -98
- package/dist/compiler/ir/visitor.d.ts.map +0 -1
- package/dist/compiler/manifest/emit.d.ts +0 -21
- package/dist/compiler/manifest/emit.d.ts.map +0 -1
- package/dist/compiler/manifest/format.d.ts +0 -119
- package/dist/compiler/manifest/format.d.ts.map +0 -1
- package/dist/compiler/manifest/index.d.ts +0 -6
- package/dist/compiler/manifest/index.d.ts.map +0 -1
- package/dist/compiler/runner/createProgram.d.ts +0 -24
- package/dist/compiler/runner/createProgram.d.ts.map +0 -1
- package/dist/compiler/runner/index.d.ts +0 -5
- package/dist/compiler/runner/index.d.ts.map +0 -1
- package/dist/compiler/schema/extractAnnotations.d.ts +0 -57
- package/dist/compiler/schema/extractAnnotations.d.ts.map +0 -1
- package/dist/compiler/schema/index.d.ts +0 -10
- package/dist/compiler/schema/index.d.ts.map +0 -1
- package/dist/compiler/schema/intersectionHandler.d.ts +0 -44
- package/dist/compiler/schema/intersectionHandler.d.ts.map +0 -1
- package/dist/compiler/schema/objectHandler.d.ts +0 -146
- package/dist/compiler/schema/objectHandler.d.ts.map +0 -1
- package/dist/compiler/schema/openapi.d.ts +0 -71
- package/dist/compiler/schema/openapi.d.ts.map +0 -1
- package/dist/compiler/schema/parameters.d.ts +0 -90
- package/dist/compiler/schema/parameters.d.ts.map +0 -1
- package/dist/compiler/schema/partitioner.d.ts +0 -85
- package/dist/compiler/schema/partitioner.d.ts.map +0 -1
- package/dist/compiler/schema/primitives.d.ts +0 -68
- package/dist/compiler/schema/primitives.d.ts.map +0 -1
- package/dist/compiler/schema/queryBuilderAnalyzer.d.ts +0 -95
- package/dist/compiler/schema/queryBuilderAnalyzer.d.ts.map +0 -1
- package/dist/compiler/schema/queryBuilderSchemaBuilder.d.ts +0 -13
- package/dist/compiler/schema/queryBuilderSchemaBuilder.d.ts.map +0 -1
- package/dist/compiler/schema/serviceCallAnalyzer.d.ts +0 -102
- package/dist/compiler/schema/serviceCallAnalyzer.d.ts.map +0 -1
- package/dist/compiler/schema/splitOpenapi.d.ts +0 -46
- package/dist/compiler/schema/splitOpenapi.d.ts.map +0 -1
- package/dist/compiler/schema/typeToJsonSchema.d.ts +0 -26
- package/dist/compiler/schema/typeToJsonSchema.d.ts.map +0 -1
- package/dist/compiler/schema/types.d.ts +0 -70
- package/dist/compiler/schema/types.d.ts.map +0 -1
- package/dist/compiler/schema/unionHandler.d.ts +0 -70
- package/dist/compiler/schema/unionHandler.d.ts.map +0 -1
- package/dist/compiler/transform/dedup.d.ts +0 -35
- package/dist/compiler/transform/dedup.d.ts.map +0 -1
- package/dist/compiler/transform/flatten.d.ts +0 -50
- package/dist/compiler/transform/flatten.d.ts.map +0 -1
- package/dist/compiler/transform/index.d.ts +0 -7
- package/dist/compiler/transform/index.d.ts.map +0 -1
- package/dist/compiler/transform/inline.d.ts +0 -46
- package/dist/compiler/transform/inline.d.ts.map +0 -1
- package/dist/compiler/validation/emitPrecompiledValidators.d.ts +0 -62
- package/dist/compiler/validation/emitPrecompiledValidators.d.ts.map +0 -1
- package/dist/compiler/validation/index.d.ts +0 -5
- package/dist/compiler/validation/index.d.ts.map +0 -1
- package/dist/decorators/Auth.d.ts +0 -22
- package/dist/decorators/Auth.d.ts.map +0 -1
- package/dist/decorators/Controller.d.ts +0 -17
- package/dist/decorators/Controller.d.ts.map +0 -1
- package/dist/decorators/Public.d.ts +0 -15
- package/dist/decorators/Public.d.ts.map +0 -1
- package/dist/decorators/Use.d.ts +0 -23
- package/dist/decorators/Use.d.ts.map +0 -1
- package/dist/decorators/methods.d.ts +0 -26
- package/dist/decorators/methods.d.ts.map +0 -1
- package/dist/express.cjs +0 -1186
- package/dist/express.cjs.map +0 -1
- package/dist/express.d.ts +0 -8
- package/dist/express.d.ts.map +0 -1
- package/dist/express.js +0 -1150
- package/dist/express.js.map +0 -1
- package/dist/http.d.ts +0 -33
- package/dist/http.d.ts.map +0 -1
- package/dist/index.cjs +0 -724
- package/dist/index.cjs.map +0 -1
- package/dist/metal/applyListQuery.d.ts +0 -100
- package/dist/metal/applyListQuery.d.ts.map +0 -1
- package/dist/metal/index.cjs +0 -278
- package/dist/metal/index.cjs.map +0 -1
- package/dist/metal/index.d.ts +0 -15
- package/dist/metal/index.d.ts.map +0 -1
- package/dist/metal/index.js +0 -243
- package/dist/metal/index.js.map +0 -1
- package/dist/metal/listQuery.d.ts +0 -26
- package/dist/metal/listQuery.d.ts.map +0 -1
- package/dist/metal/queryOptions.d.ts +0 -16
- package/dist/metal/queryOptions.d.ts.map +0 -1
- package/dist/metal/readMetalBag.d.ts +0 -69
- package/dist/metal/readMetalBag.d.ts.map +0 -1
- package/dist/metal/registerMetalEntities.d.ts +0 -26
- package/dist/metal/registerMetalEntities.d.ts.map +0 -1
- package/dist/metal/schemaFromEntity.d.ts +0 -41
- package/dist/metal/schemaFromEntity.d.ts.map +0 -1
- package/dist/metal/searchWhere.d.ts +0 -97
- package/dist/metal/searchWhere.d.ts.map +0 -1
- package/dist/metal/symbolMetadata.d.ts +0 -8
- package/dist/metal/symbolMetadata.d.ts.map +0 -1
- package/dist/runtime/auth/runtime.d.ts +0 -183
- package/dist/runtime/auth/runtime.d.ts.map +0 -1
- package/dist/runtime/metadata/bucket.d.ts +0 -2
- package/dist/runtime/metadata/bucket.d.ts.map +0 -1
- package/dist/runtime/metadata/key.d.ts +0 -2
- package/dist/runtime/metadata/key.d.ts.map +0 -1
- package/dist/runtime/metadata/read.d.ts +0 -2
- package/dist/runtime/metadata/read.d.ts.map +0 -1
- package/dist/runtime/metadata/types.d.ts +0 -95
- package/dist/runtime/metadata/types.d.ts.map +0 -1
- package/dist/runtime/polyfill.d.ts +0 -2
- package/dist/runtime/polyfill.d.ts.map +0 -1
- package/dist/runtime/upload.d.ts +0 -44
- package/dist/runtime/upload.d.ts.map +0 -1
- package/dist/runtime/validation/ajv.d.ts +0 -120
- package/dist/runtime/validation/ajv.d.ts.map +0 -1
- package/dist/runtime/validation/index.d.ts +0 -11
- package/dist/runtime/validation/index.d.ts.map +0 -1
- package/dist/schema/decorators.d.ts +0 -37
- package/dist/schema/decorators.d.ts.map +0 -1
- package/dist/schema/index.cjs +0 -214
- package/dist/schema/index.cjs.map +0 -1
- package/dist/schema/index.d.ts +0 -2
- package/dist/schema/index.d.ts.map +0 -1
- package/dist/schema/index.js +0 -163
- package/dist/schema/index.js.map +0 -1
- package/dist/scripts/adorn-example.cjs +0 -404
- package/dist/scripts/adorn-example.cjs.map +0 -1
- package/dist/utils/operationId.d.ts +0 -2
- package/dist/utils/operationId.d.ts.map +0 -1
- package/dist/utils/path.d.ts +0 -2
- package/dist/utils/path.d.ts.map +0 -1
- package/dist/utils/port.d.ts +0 -9
- package/dist/utils/port.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -1,531 +1,375 @@
|
|
|
1
|
-
# Adorn
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
```typescript
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
```typescript
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
@
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
@
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
@
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
@
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
`
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
###
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
Use,
|
|
377
|
-
Auth,
|
|
378
|
-
Public,
|
|
379
|
-
} from "adorn-api";
|
|
380
|
-
|
|
381
|
-
import {
|
|
382
|
-
bootstrap,
|
|
383
|
-
createExpressRouter,
|
|
384
|
-
setupSwagger,
|
|
385
|
-
} from "adorn-api/express";
|
|
386
|
-
|
|
387
|
-
import {
|
|
388
|
-
ListQuery,
|
|
389
|
-
applyListQuery,
|
|
390
|
-
registerMetalEntities,
|
|
391
|
-
} from "adorn-api/metal";
|
|
392
|
-
|
|
393
|
-
import { readAdornBucket } from "adorn-api";
|
|
394
|
-
import type { AdornBucket, AuthSchemeRuntime, AuthResult } from "adorn-api";
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
### Bootstrap Options
|
|
398
|
-
|
|
399
|
-
```typescript
|
|
400
|
-
await bootstrap({
|
|
401
|
-
controllers: [UserController, PostController],
|
|
402
|
-
auth: {
|
|
403
|
-
schemes: {
|
|
404
|
-
BearerAuth: bearerRuntime,
|
|
405
|
-
ApiKey: apiKeyRuntime,
|
|
406
|
-
},
|
|
407
|
-
},
|
|
408
|
-
middleware: {
|
|
409
|
-
global: [logger, cors],
|
|
410
|
-
named: { auth: authMiddleware },
|
|
411
|
-
},
|
|
412
|
-
port: 3000,
|
|
413
|
-
host: "0.0.0.0",
|
|
414
|
-
});
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
### Auth Scheme
|
|
418
|
-
|
|
419
|
-
```typescript
|
|
420
|
-
const authScheme: AuthSchemeRuntime = {
|
|
421
|
-
name: "MyAuth",
|
|
422
|
-
async authenticate(req: any) {
|
|
423
|
-
return { principal: user, scopes: ["read", "write"] };
|
|
424
|
-
},
|
|
425
|
-
challenge(res: any) {
|
|
426
|
-
res.status(401).json({ error: "Unauthorized" });
|
|
427
|
-
},
|
|
428
|
-
authorize(auth: any, requiredScopes: string[]) {
|
|
429
|
-
return requiredScopes.every(s => auth.scopes?.includes(s));
|
|
430
|
-
},
|
|
431
|
-
};
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
## Validation
|
|
435
|
-
|
|
436
|
-
Adorn-API supports two validation modes:
|
|
437
|
-
|
|
438
|
-
### Runtime Validation (AJV)
|
|
439
|
-
|
|
440
|
-
```typescript
|
|
441
|
-
await bootstrap({
|
|
442
|
-
controllers: [UserController],
|
|
443
|
-
validation: {
|
|
444
|
-
mode: "ajv-runtime",
|
|
445
|
-
},
|
|
446
|
-
});
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
### Precompiled Validators
|
|
450
|
-
|
|
451
|
-
```typescript
|
|
452
|
-
await bootstrap({
|
|
453
|
-
controllers: [UserController],
|
|
454
|
-
validation: {
|
|
455
|
-
mode: "precompiled",
|
|
456
|
-
},
|
|
457
|
-
});
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
Precompiled validators are generated at build time in `.adorn/validator.js` for better performance.
|
|
461
|
-
|
|
462
|
-
## Testing
|
|
463
|
-
|
|
464
|
-
Tests are written with Vitest and cover:
|
|
465
|
-
|
|
466
|
-
- Compiler schema generation
|
|
467
|
-
- Decorator metadata
|
|
468
|
-
- Express integration
|
|
469
|
-
- Middleware execution order
|
|
470
|
-
- Authentication and authorization
|
|
471
|
-
- Metal-ORM integration
|
|
472
|
-
|
|
473
|
-
```bash
|
|
474
|
-
npm test
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
### Test Structure
|
|
478
|
-
|
|
479
|
-
```
|
|
480
|
-
test/
|
|
481
|
-
├── integration/ # Express integration tests
|
|
482
|
-
├── compiler/ # Schema and manifest generation
|
|
483
|
-
├── runtime/ # Decorator metadata
|
|
484
|
-
├── middleware/ # Middleware ordering and auth
|
|
485
|
-
├── metal/ # Metal-ORM integration
|
|
486
|
-
└── fixtures/ # Test fixtures
|
|
487
|
-
```
|
|
488
|
-
|
|
489
|
-
## Configuration
|
|
490
|
-
|
|
491
|
-
### TypeScript Config
|
|
492
|
-
|
|
493
|
-
```json
|
|
494
|
-
{
|
|
495
|
-
"compilerOptions": {
|
|
496
|
-
"target": "ES2022",
|
|
497
|
-
"module": "ES2022",
|
|
498
|
-
"moduleResolution": "bundler",
|
|
499
|
-
"experimentalDecorators": true,
|
|
500
|
-
"emitDecoratorMetadata": true
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
### Vitest Config
|
|
506
|
-
|
|
507
|
-
```typescript
|
|
508
|
-
import { defineConfig } from "vitest/config";
|
|
509
|
-
|
|
510
|
-
export default defineConfig({
|
|
511
|
-
test: {
|
|
512
|
-
include: ["test/**/*.test.ts"],
|
|
513
|
-
typecheck: {
|
|
514
|
-
enabled: true,
|
|
515
|
-
tsconfig: "./tsconfig.json",
|
|
516
|
-
},
|
|
517
|
-
},
|
|
518
|
-
});
|
|
519
|
-
```
|
|
520
|
-
|
|
521
|
-
## How It Works
|
|
522
|
-
|
|
523
|
-
1. **Compile**: The CLI analyzes your TypeScript controllers and extracts metadata using the compiler API
|
|
524
|
-
2. **Generate**: OpenAPI schemas and runtime manifests are generated from type information
|
|
525
|
-
3. **Bind**: At runtime, metadata is merged with controller instances to bind routes to Express
|
|
526
|
-
4. **Validate**: Optional validation ensures requests match your TypeScript types
|
|
527
|
-
5. **Document**: Swagger UI serves interactive documentation based on generated OpenAPI spec
|
|
528
|
-
|
|
529
|
-
## License
|
|
530
|
-
|
|
531
|
-
MIT
|
|
1
|
+
# Adorn API
|
|
2
|
+
|
|
3
|
+
Decorator-first web framework with OpenAPI 3.1 schema generation, built on top of Express.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Decorator-First API**: Define APIs using TypeScript decorators for controllers, routes, and DTOs
|
|
8
|
+
- **Automatic OpenAPI 3.1 Generation**: Swagger UI documentation auto-generated from your code
|
|
9
|
+
- **Type-Safe DTOs**: Data Transfer Objects with built-in validation and serialization
|
|
10
|
+
- **Input Coercion**: Automatic type conversion and validation of HTTP inputs
|
|
11
|
+
- **Error Handling**: Comprehensive error handling with custom error responses
|
|
12
|
+
- **Metal ORM Integration**: Built-in support for Metal ORM with CRUD operations and pagination
|
|
13
|
+
- **Express Integration**: Lightweight adapter for Express.js
|
|
14
|
+
- **Type Safety**: Full TypeScript support with type inferencing
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install adorn-api
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### 1. Define DTOs
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { Dto, Field, OmitDto, PickDto, t } from "adorn-api";
|
|
28
|
+
|
|
29
|
+
@Dto({ description: "User record returned by the API." })
|
|
30
|
+
export class UserDto {
|
|
31
|
+
@Field(t.uuid({ description: "User identifier." }))
|
|
32
|
+
id!: string;
|
|
33
|
+
|
|
34
|
+
@Field(t.string({ minLength: 1 }))
|
|
35
|
+
name!: string;
|
|
36
|
+
|
|
37
|
+
@Field(t.optional(t.string()))
|
|
38
|
+
nickname?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@OmitDto(UserDto, ["id"])
|
|
42
|
+
export class CreateUserDto {}
|
|
43
|
+
|
|
44
|
+
@PickDto(UserDto, ["id"])
|
|
45
|
+
export class UserParamsDto {}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. Create a Controller
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import {
|
|
52
|
+
Body,
|
|
53
|
+
Controller,
|
|
54
|
+
Get,
|
|
55
|
+
Params,
|
|
56
|
+
Post,
|
|
57
|
+
Returns,
|
|
58
|
+
type RequestContext
|
|
59
|
+
} from "adorn-api";
|
|
60
|
+
import { CreateUserDto, UserDto, UserParamsDto } from "./user.dtos";
|
|
61
|
+
|
|
62
|
+
@Controller("/users")
|
|
63
|
+
export class UserController {
|
|
64
|
+
@Get("/:id")
|
|
65
|
+
@Params(UserParamsDto)
|
|
66
|
+
@Returns(UserDto)
|
|
67
|
+
async getOne(ctx: RequestContext<unknown, undefined, { id: string }>) {
|
|
68
|
+
return {
|
|
69
|
+
id: ctx.params.id,
|
|
70
|
+
name: "Ada Lovelace",
|
|
71
|
+
nickname: "Ada"
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@Post("/")
|
|
76
|
+
@Body(CreateUserDto)
|
|
77
|
+
@Returns({ status: 201, schema: UserDto, description: "Created" })
|
|
78
|
+
async create(ctx: RequestContext<CreateUserDto>) {
|
|
79
|
+
return {
|
|
80
|
+
id: "3f0f4d0f-1cb1-4cf1-9c32-3d4bce1b3f36",
|
|
81
|
+
name: ctx.body.name,
|
|
82
|
+
nickname: ctx.body.nickname
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 3. Create and Start the App
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { createExpressApp } from "adorn-api";
|
|
92
|
+
import { UserController } from "./user.controller";
|
|
93
|
+
|
|
94
|
+
export function createApp() {
|
|
95
|
+
return createExpressApp({
|
|
96
|
+
controllers: [UserController],
|
|
97
|
+
openApi: {
|
|
98
|
+
info: {
|
|
99
|
+
title: "Adorn API",
|
|
100
|
+
version: "1.0.0"
|
|
101
|
+
},
|
|
102
|
+
docs: true
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Start the server
|
|
108
|
+
const app = createApp();
|
|
109
|
+
app.listen(3000, () => {
|
|
110
|
+
console.log("Server running on http://localhost:3000");
|
|
111
|
+
console.log("Documentation available at http://localhost:3000/docs");
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Documentation
|
|
116
|
+
|
|
117
|
+
### Controllers
|
|
118
|
+
|
|
119
|
+
Controllers are classes decorated with `@Controller()` that group related API endpoints.
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
@Controller("/api/v1/users")
|
|
123
|
+
export class UserController {
|
|
124
|
+
// Endpoints here
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Routes
|
|
129
|
+
|
|
130
|
+
Routes are methods decorated with HTTP method decorators:
|
|
131
|
+
|
|
132
|
+
- `@Get(path)` - GET request
|
|
133
|
+
- `@Post(path)` - POST request
|
|
134
|
+
- `@Put(path)` - PUT request
|
|
135
|
+
- `@Patch(path)` - PATCH request
|
|
136
|
+
- `@Delete(path)` - DELETE request
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
@Get("/")
|
|
140
|
+
@Returns(t.array(UserDto))
|
|
141
|
+
async listUsers() {
|
|
142
|
+
return users;
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Inputs
|
|
147
|
+
|
|
148
|
+
Use decorators to define and validate request inputs:
|
|
149
|
+
|
|
150
|
+
- `@Body(schema)` - Request body
|
|
151
|
+
- `@Query(schema)` - Query parameters
|
|
152
|
+
- `@Params(schema)` - Path parameters
|
|
153
|
+
- `@Headers(schema)` - Request headers
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
@Get("/:id")
|
|
157
|
+
@Params(UserParamsDto)
|
|
158
|
+
@Query(PaginationDto)
|
|
159
|
+
@Returns(UserDto)
|
|
160
|
+
async getUser(ctx: RequestContext<unknown, PaginationDto, { id: string }>) {
|
|
161
|
+
// ctx.params.id is typed as string
|
|
162
|
+
// ctx.query is typed as PaginationDto
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Responses
|
|
167
|
+
|
|
168
|
+
Use `@Returns()` decorator to document responses:
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
@Returns(UserDto) // 200 OK with UserDto
|
|
172
|
+
@Returns({ status: 201, schema: UserDto, description: "Created" })
|
|
173
|
+
@ReturnsError(ValidationErrorDto) // 400+ error response
|
|
174
|
+
@Errors(ApiErrorDto, [
|
|
175
|
+
{ status: 404, description: "Not Found" },
|
|
176
|
+
{ status: 401, description: "Unauthorized" }
|
|
177
|
+
])
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### DTOs (Data Transfer Objects)
|
|
181
|
+
|
|
182
|
+
DTOs define the shape of data sent to and from your API:
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
@Dto({
|
|
186
|
+
description: "User data",
|
|
187
|
+
additionalProperties: false // Disallow extra properties
|
|
188
|
+
})
|
|
189
|
+
export class UserDto {
|
|
190
|
+
@Field(t.uuid({ description: "Unique identifier" }))
|
|
191
|
+
id!: string;
|
|
192
|
+
|
|
193
|
+
@Field(t.string({
|
|
194
|
+
minLength: 1,
|
|
195
|
+
maxLength: 100,
|
|
196
|
+
description: "Full name"
|
|
197
|
+
}))
|
|
198
|
+
name!: string;
|
|
199
|
+
|
|
200
|
+
@Field(t.optional(t.email({ description: "Email address" })))
|
|
201
|
+
email?: string;
|
|
202
|
+
|
|
203
|
+
@Field(t.array(t.string({ description: "User roles" })))
|
|
204
|
+
roles!: string[];
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### DTO Composition
|
|
209
|
+
|
|
210
|
+
Create new DTOs by composing existing ones:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
// Pick specific fields
|
|
214
|
+
@PickDto(UserDto, ["id", "name"])
|
|
215
|
+
export class UserSummaryDto {}
|
|
216
|
+
|
|
217
|
+
// Omit specific fields
|
|
218
|
+
@OmitDto(UserDto, ["password"])
|
|
219
|
+
export class PublicUserDto {}
|
|
220
|
+
|
|
221
|
+
// Make all fields optional
|
|
222
|
+
@PartialDto(UserDto)
|
|
223
|
+
export class UpdateUserDto {}
|
|
224
|
+
|
|
225
|
+
// Merge multiple DTOs
|
|
226
|
+
@MergeDto([UserDto, AddressDto])
|
|
227
|
+
export class UserWithAddressDto {}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Schema Types
|
|
231
|
+
|
|
232
|
+
The `t` (type) object provides schema builders for all JSON types:
|
|
233
|
+
|
|
234
|
+
- Primitives: `t.string()`, `t.number()`, `t.integer()`, `t.boolean()`, `t.null()`
|
|
235
|
+
- Formats: `t.uuid()`, `t.email()`, `t.dateTime()`
|
|
236
|
+
- Complex: `t.array()`, `t.object()`, `t.record()`
|
|
237
|
+
- Composition: `t.union()`, `t.enum()`, `t.literal()`
|
|
238
|
+
- References: `t.ref()`
|
|
239
|
+
- Modifiers: `t.optional()`, `t.nullable()`
|
|
240
|
+
|
|
241
|
+
### Metal ORM Integration
|
|
242
|
+
|
|
243
|
+
Adorn provides seamless integration with Metal ORM:
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
import {
|
|
247
|
+
MetalDto,
|
|
248
|
+
createMetalCrudDtos,
|
|
249
|
+
parsePagination,
|
|
250
|
+
type RequestContext
|
|
251
|
+
} from "adorn-api";
|
|
252
|
+
import { User } from "./user.entity";
|
|
253
|
+
|
|
254
|
+
// Generate CRUD DTOs from Metal ORM entity
|
|
255
|
+
const {
|
|
256
|
+
CreateDto,
|
|
257
|
+
UpdateDto,
|
|
258
|
+
ReplaceDto,
|
|
259
|
+
ResponseDto,
|
|
260
|
+
ParamsDto
|
|
261
|
+
} = createMetalCrudDtos(User);
|
|
262
|
+
|
|
263
|
+
@Controller("/users")
|
|
264
|
+
export class UserController {
|
|
265
|
+
@Get("/")
|
|
266
|
+
@Query(PaginationQueryDto)
|
|
267
|
+
@Returns(ResponseDto)
|
|
268
|
+
async list(ctx: RequestContext<unknown, PaginationQueryDto>) {
|
|
269
|
+
const { page, pageSize } = parsePagination(ctx.query);
|
|
270
|
+
// Query with pagination...
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
@Post("/")
|
|
274
|
+
@Body(CreateDto)
|
|
275
|
+
@Returns({ status: 201, schema: ResponseDto })
|
|
276
|
+
async create(ctx: RequestContext<typeof CreateDto>) {
|
|
277
|
+
// Create user...
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Error Handling
|
|
283
|
+
|
|
284
|
+
Throw `HttpError` for HTTP error responses:
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
import { HttpError } from "adorn-api";
|
|
288
|
+
|
|
289
|
+
throw new HttpError(404, "User not found");
|
|
290
|
+
|
|
291
|
+
// With custom body and headers
|
|
292
|
+
throw new HttpError({
|
|
293
|
+
status: 400,
|
|
294
|
+
message: "Validation failed",
|
|
295
|
+
body: {
|
|
296
|
+
errors: ["Email is invalid", "Password is too short"]
|
|
297
|
+
},
|
|
298
|
+
headers: { "X-Error-Code": "VALIDATION_ERROR" }
|
|
299
|
+
});
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### OpenAPI Configuration
|
|
303
|
+
|
|
304
|
+
Customize the OpenAPI generation:
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
createExpressApp({
|
|
308
|
+
controllers: [UserController],
|
|
309
|
+
openApi: {
|
|
310
|
+
info: {
|
|
311
|
+
title: "My API",
|
|
312
|
+
version: "2.0.0",
|
|
313
|
+
description: "API documentation"
|
|
314
|
+
},
|
|
315
|
+
servers: [
|
|
316
|
+
{ url: "https://api.example.com/v1", description: "Production" },
|
|
317
|
+
{ url: "http://localhost:3000", description: "Development" }
|
|
318
|
+
],
|
|
319
|
+
path: "/api-docs.json", // OpenAPI JSON endpoint
|
|
320
|
+
docs: {
|
|
321
|
+
path: "/api-docs", // Swagger UI path
|
|
322
|
+
title: "API Documentation",
|
|
323
|
+
swaggerUiUrl: "https://unpkg.com/swagger-ui-dist@5"
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Input Coercion
|
|
330
|
+
|
|
331
|
+
Configure input coercion behavior:
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
createExpressApp({
|
|
335
|
+
controllers: [UserController],
|
|
336
|
+
inputCoercion: "strict" // "safe" (default), "strict", or false
|
|
337
|
+
});
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
- **safe**: Attempt to coerce values to the expected type
|
|
341
|
+
- **strict**: Throw errors for invalid inputs
|
|
342
|
+
- **false**: Disable coercion entirely
|
|
343
|
+
|
|
344
|
+
## Examples
|
|
345
|
+
|
|
346
|
+
Check the `examples/` directory for complete examples:
|
|
347
|
+
|
|
348
|
+
- **basic**: Simple API with DTOs and controllers
|
|
349
|
+
- **metal-orm-sqlite**: Full CRUD API with Metal ORM and SQLite
|
|
350
|
+
- **metal-orm-sqlite-music**: Complex API with relationships
|
|
351
|
+
- **restful**: RESTful API example
|
|
352
|
+
- **openapi**: OpenAPI customization example
|
|
353
|
+
|
|
354
|
+
## Build and Test
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
# Install dependencies
|
|
358
|
+
npm install
|
|
359
|
+
|
|
360
|
+
# Build the library
|
|
361
|
+
npm run build
|
|
362
|
+
|
|
363
|
+
# Run tests
|
|
364
|
+
npm test
|
|
365
|
+
|
|
366
|
+
# Run tests in watch mode
|
|
367
|
+
npm run test:watch
|
|
368
|
+
|
|
369
|
+
# Run an example
|
|
370
|
+
npm run example -- basic
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
## License
|
|
374
|
+
|
|
375
|
+
MIT
|