diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index e204da9c88a..2ede5a638a2 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -145,7 +145,8 @@ module.exports = { "/docs/injection-scopes", "/docs/custom-providers", "/docs/custom-endpoint-decorators", - "/docs/testing" + "/docs/testing", + "/api" ] }, { diff --git a/docs/api.md b/docs/api.md index 2a98778e387..2e36ac10d7b 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,6 +1,12 @@ --- -sidebar: false +meta: + - name: description + content: Api Reference of Ts.ED. Use decorator to build your model and map data. + - name: keywords + content: api reference model decorators ts.ed express typescript node.js javascript jsonschema json mapper serialization deserialization --- # Api Reference +
+ \ No newline at end of file diff --git a/docs/docs/converters.md b/docs/docs/converters.md index 202399c1f2d..0fc5ad171be 100644 --- a/docs/docs/converters.md +++ b/docs/docs/converters.md @@ -15,17 +15,20 @@ It uses all decorators from `@tsed/schema` package and TypeScript metadata to wo Ts.ED use this package to transform any input parameters sent by your consumer to a class and transform returned value by your endpoint to a plain javascript object to your consumer. -::: warning -For v5 developer, this package is the new API under the @@ConverterService@@. There are some breaking changes between the previous service implementation: +::: warning Breaking change +For v5 developer, `@tsed/json-mapper` package is the new API under the @@ConverterService@@. There are some breaking changes between the previous service implementation: - The `@Converter` decorator have been removed in favor of @@JsonMapper@@ decorator. -- Classes like `ArrayConverter`, `SetConverter`, etc... replaced by his equivalents @@ArrayMapper@@, @@SetMapper@@, etc... These classes cannot be injected to another provider. +- Classes like `ArrayConverter`, `SetConverter`, etc... replaced by his equivalents Types mapper: @@ArrayMapper@@, @@SetMapper@@, etc... +- Type mapper classes are no longer injectable services. - ConverterService is always available and can be injected to another provider, but now, ConverterService doesn't perform data validation. Validation is performed by [`@tsed/ajv`](/tutorials/ajv.md) package or any other validation library. +- `PropertyDeserialize` and `PropertySerialize` have been removed and replaced by @@OnDeserialize@@ and @@OnSerialize@@. +- Methods Signatures of Type mapper (like ArrayConverter) have changed. ::: ## Usage -JsonMapper work with a class and decorators. Use decorators on properties to describe a model and use this model as an input parameter or return value by your endpoint. Here is a model example: +JsonMapper works with a class and decorators. Use decorators on properties to describe a model and use this model as an input parameter or return value by your endpoint. Here is a model example: @@ -45,7 +48,9 @@ JsonMapper work with a class and decorators. Use decorators on properties to des -> Note: Take a look on Jest/Mocha tabs to see @@serialize@@ and @@deserialize@@ functions usage. +::: tip Note +Take a look on Jest/Mocha tabs to see @@serialize@@ and @@deserialize@@ functions usage. +::: Now we can use the `Person` model on a controller: @@ -161,12 +166,14 @@ export class Person { `@tsed/json-mapper` use classes to transform an input value to the expected value: -- Primitives: @@PrimitiveMapper@@, -- Symbol: @@SymbolMapper@@, -- Objects: @@DateMapper@@, -- Collections: @@ArrayMapper@@, @@MapMapper@@ and @@SetMapper@@. +Type | Mapper +---|--- +Primitives | @@PrimitiveMapper@@, +Symbol | @@SymbolMapper@@, +Objects | @@DateMapper@@, +Collections | @@ArrayMapper@@, @@MapMapper@@ and @@SetMapper@@. -It's possible de to change add your own type mapper by using the @@JsonMapper@@ decorator on a class. Just copy a mapper implementation +It's possible to add your own type mapper by using the @@JsonMapper@@ decorator on a class. Just copy a mapper implementation and import the mapper in your application. ### Primitives diff --git a/docs/docs/platform-api.md b/docs/docs/platform-api.md index 9b81c1ecf07..547d79b0365 100644 --- a/docs/docs/platform-api.md +++ b/docs/docs/platform-api.md @@ -1,7 +1,7 @@ # Platform API Ts.ED use now, the Platform API to create an application. Platform API give an abstraction layer between your code written with Ts.ED and the [Express.js](https://expressjs.com/fr/) code. -It means, a large part of your code isn't coupled with Express itself and can be used with another Platform like [Koa.js](https://koajs.com/) in future (Ts.ED v6). +It means, a large part of your code isn't coupled with Express.js itself and can be used with another Platform like [Koa.js](https://koajs.com/). There are some changes between ServerLoader API (v4/v5) and Platform API (v5.56.0+/v6), to get the original Express Application, Request or Response. This page will describe how you can get these instance with the new API. @@ -19,7 +19,7 @@ This page will describe how you can get these instance with the new API. ## Create application -The way to create Ts.ED application, add [middlewares](/docs/middlewares.html), configure Express.Application are impacted by the new Platform API. +The way to create Ts.ED application, add [middlewares](/docs/middlewares.html), configure Express or Koa are impacted by the new Platform API. If you use @@ServerLoader@@, you'll probably know this example to create a Ts.ED application: @@ -71,7 +71,10 @@ export const rootDir = __dirname; @Configuration({ rootDir, - viewsDir: `${rootDir}/views` + views: { + root: `${rootDir}/views`, + viewEngine: 'ejs' + } }) export class Server { @Constant("viewsDir") @@ -90,10 +93,6 @@ export class Server { .use(bodyParser.urlencoded({ extended: true })); - - // configure express app - this.app.raw.set("views", this.viewsDir); - this.app.raw.engine("ejs", ejs); } } ``` diff --git a/docs/getting-started/migration-from-v5.md b/docs/getting-started/migration-from-v5.md index cc205b9b794..b20aad52d2f 100644 --- a/docs/getting-started/migration-from-v5.md +++ b/docs/getting-started/migration-from-v5.md @@ -9,38 +9,257 @@ meta: content: migration getting started ts.ed express typescript node.js javascript decorators mvc class models --- # Migrate from v5 - ## What's news ? +### Platform API + +V6 marks a major evolution of the Ts.ED framework. +A lot of work has been done on the internal Ts.ED code since v5 in order to prepare the arrival of this new version. +This work was mainly oriented on the creation of an abstraction layer between the Ts.ED framework and Express.js. + + The v5 introduced the [Platform API](/docs/platform-api.md) +and the v6 is the confirmation of this API which allows supporting [Express.js](https://expressjs.com/) and [Koa.js](https://koajs.com/) and many more in the future. + +We are glad this work resulted in the creation of the [@tsed/platform-express](/https://www.npmjs.com/package/@tsed/platform-express) and +[@tsed/platform-koa](/https://www.npmjs.com/package/@tsed/platform-koa). + +::: tip See also + +- Template engine: [Configure template engine with Platform API](/docs/templating.md). +- Statics files: [Configure statics files with Platform API](/docs/serve-files.md). +- Upload files: [Multer is now a part of @tsed/common](/docs/serve-files.md). + +::: + +### Schema and OpenSpec + +This release finally adds support for [OpenSpec 3](https://swagger.io/docs/specification/about/) while supporting +the previous version [Swagger2](https://swagger.io/docs/specification/2-0/basic-structure/). +The management of OpenSpec is at the heart of the framework as is [JsonSchema](https://json-schema.org/). + +All decorators related to the declaration of schema, routes and endpoints are now integrated in a single module [`@tsed/schema`](https://www.npmjs.com/package/@tsed/schema). +This module has been designed to be used independently of the Ts.ED framework. +You can therefore use it for your projects without installing the whole framework! +::: tip See also +New features are available: + +- Managing models using Typescript generics. +- Management response models by content-type and status code (OAS3). +- Configure swagger to generate OpenSpec3. + +::: + +### JsonMapper + +In the same idea, the convertersService code was taken out of the [`@tsed/common`](https://www.npmjs.com/package/@tsed/common) module + to the new [`@tsed/json-mapper`](https://www.npmjs.com/package/@tsed/json-mapper) module. + It's based on the [`@tsed/schema`](https://www.npmjs.com/package/@tsed/schema) module to perform the mapping of your classes + to a Plain Object JavaScript object and vice versa. + +You can therefore use it for your projects without installing the whole framework! + +::: tip See also + +- @@Ignore@@ decorator accept a callback to define when the property should be ignored! +- @@serialize@@ and @@deserialize@@ function can be used in place of @@ConverterService@@. +- `@Converter` have been replaced in favor of @@JsonMapper@@. See our [migration guide](/gettings-started/migration-from-v5.md#converter-to-jsonmapper). + +::: + ## Breaking changes +### Api & Features + +- `ServerLoader` API have been remove in favor of Platform API. See [Platform API](/docs/platform-api.md). +- `Filter` feature have been removed in favor of [Pipes](/docs/pipes.md). +- `GlobalErrorHandlerMiddleware` have been.removed in favor of [Exception Filters](/docs/exceptions.md#exception-filter). +- @@ConverterService@@ doesn't perform data validation. Validation is performed by [`@tsed/ajv`](/tutorials/ajv.md) package or any other validation library. + +### Modules + +The following modules have been removed: + +- `@tsed/testing`: Use @@PlatformTest@@ from `@tsed/common`. +- `@tsed/multipartfiles`: Use @@MultipartFile@@ from `@tsed/common`. +- `ts-express-decorators`: Use `@tsed/common`. + +### Decorators + +The following decorators have been removed: + +#### @tsed/di + +- `@OverrideService`: Use @@OverrideProvider@@ + +#### @tsed/common + +- `@ServerSettings`: Use @@Configuration@@. +- `@ExpressApplication`: Use @@PlatformApplication@@ instead of. +- `@ExpressRouter`: Use @@PlatformRouter@@ instead of. +- `@ResponseView`: Use @@View@@ decorator instead of. +- `@Filter`: Filter feature have been removed. +- `@MiddlewareError`: Use @@Middleware@@. +- `@Converter`: @Converter is replaced by @@JsonMapper@@ from `@tsed/json-mapper`. See [Converter to JsonMapper](/getting-started/migration-from-v5.md#converter-to-jsonmapper) section for more details. +- `PropertyDeserialize` and `PropertySerialize` have been removed and replaced by @@OnDeserialize@@ and @@OnSerialize@@ from `@tsed/json-mapper`. + +#### @tsed/typeorm + +- `@EntityRepository`: Use EntityRepository from `typeorm` directly. + +#### @tsed/swagger + +Import the following decorators from `@tsed/schema`: + + + +- `@BaseParameter` have been removed. +- `@Operation` have been removed. +- `@Responses` have been remove. +- `@ReturnsArray` have been removed. Use @@Returns@@ from `@tsed/schema`. + +### Classes + +#### @tsed/common + +- Classes like `ArrayConverter`, `SetConverter`, etc... replaced by his equivalents @@ArrayMapper@@, @@SetMapper@@, etc... These classes cannot be injected to another provider. + +## Migration guide +### ServerLoader to Platform API -## GlobalErrorHandler middleware to Exception filter +All change related to [Platform API](/docs/platform-api.md) and how to migrate the Server on this new API, is described on a dedicated page. +We encourage you to browse the entire page to migrate from v4/v5 to v6. -[Exception filter]() is the +See our [Platform API](/docs/platform-api.md) documentation page. -To facilitate your migration, remove the line where you add you custom middleware in the server: +### Inject service in the Server + +With @@ServerLoader@@, inject a provider can be done as follows: ```typescript -$afterRoutesInit() { - this.app.use(CustomGlobalErrorHandlerMiddleware); // remove this +import {ServerLoader, ServerSettings} from "@tsed/common"; +import {MyService} from "./services/MyService"; + +@ServerLoader({ +}) +export class Server extends ServerLoader { + $beforeRoutesInit() { + const myService = this.injector.get(MyService); + + myService.getSomething(); + } } ``` -Then, use the @@OverrideProvider@@ decorator over your custom middleware: +Now Platform API, the Server class is considered as a @@Provider@@. +It means, you can use decorator like @@Constant@@ and @@Inject@@ to get any configuration, provider or service from the DI registry. ```typescript -import {OverrideProvider} from "@tsed/di"; -import {GlobalErrorHandlerMiddleware} from "@tsed/common"; +import {Configuration} from "@tsed/common"; +import {Inject} from "@tsed/di"; +import {MyService} from "./services/MyService"; + +@Configuration({}) +export class Server { + @Inject() + myService: MyService; + + $beforeRoutesInit() { + this.myService.getSomething(); + } +} +``` + +### GlobalErrorHandler to Exception Filter + +::: warning Breaking changes -@OverrideProvider(GlobalErrorHandlerMiddleware) -export class CustomGlobalErrorHandlerMiddleware extends GlobalErrorHandlerMiddleware { +- CustomGlobalErrorHandlerMiddleware have been removed. +- Default [Exception Filter](/docs/exceptions.html#exception-filter) returns a Json object to your consumer. +::: + +To fix that, remove the line where you add you custom middleware in the server: + +```typescript +class Server { + $afterRoutesInit() { + this.app.use(CustomGlobalErrorHandlerMiddleware); // remove this + } } ``` -Now you are able to create your own exception filter. Start with the HttpException example: +::: tip +To migrate your `CustomGlobalErrorHandlerMiddleware` to create an exception filter. +See our [Exception Filter](/docs/exceptions.html#exception-filter) documentation page to know what is the appropriate implementation +for your use case. +::: + +Exception Filter use @@Catch@@ decorator to catch a specific instance error. For example, if you want to catch an Http exception +you have to provide the generic @@Exception@@ class to the decorator as follows: <<< @/docs/docs/snippets/exceptions/http-exception-filter.ts -Then try with another error type and finally, remove your custom middleware. \ No newline at end of file +### Converter to JsonMapper + +The `@tsed/json-mapper` package is now responsible to map a plain object to a model and a model to a plain object. + +It provides two functions @@serialize@@ and @@deserialize@@ to transform object depending on which operation you want to perform. +It uses all decorators from `@tsed/schema` package and TypeScript metadata to work. + +::: warning Breaking changes + +- The `@Converter` decorator have been removed in favor of @@JsonMapper@@ decorator. +- Classes like `ArrayConverter`, `SetConverter`, etc... replaced by his equivalents Types mapper: @@ArrayMapper@@, @@SetMapper@@, etc... +- Type mapper classes are no longer injectable services. +- ConverterService is always available and can be injected to another provider, but now, ConverterService doesn't perform data validation. Validation is performed by [`@tsed/ajv`](/tutorials/ajv.md) package or any other validation library. +- `PropertyDeserialize` and `PropertySerialize` have been removed and replaced by @@OnDeserialize@@ and @@OnSerialize@@. +- Methods signatures of Type mapper (like ArrayConverter) have changed. +::: + +Here is the `ArrayConverter` as implemented in v5: + +```typescript +import {Converter, IConverter, IDeserializer, ISerializer} from "@tsed/common"; + +@Converter(Array) +export class ArrayConverter implements IConverter { + deserialize(data: any, target: any, baseType: T, deserializer: IDeserializer): T[] { + return [].concat(data).map((item) => deserializer!(item, baseType)); + } + + serialize(data: any[], serializer: ISerializer) { + return [].concat(data as any).map((item) => serializer(item)); + } +} +``` + +Now, The new @@ArrayMapper@@ as implemented in v6: + +```typescript +import {JsonMapper, JsonMapperCtx, JsonMapperMethods} from "@tsed/json-mapper"; + +@JsonMapper(Array) +export class ArrayMapper implements JsonMapperMethods { + deserialize(data: any, options: JsonMapperCtx): T[] { + return [].concat(data).map((item) => options.next(item)); + } + + serialize(data: any[], options: JsonMapperCtx): any { + return [].concat(data as any).map((item) => options.next(item)); + } +} +``` + +To help you migrate your custom mapper, here is a small table of equivalent points between v5 and v6: + +V5 | V6 | Description +---|---|--- +Converter | JsonMapper | The decorator have the same behavior. You can use JsonMapper to override an existing mapper. +deserializer/serializer | options.next(item) | Call the next function to deserialize/serialize object. +target/baseType | JsonMapperCtx.type/JsonMapperCtx.collectionType | The types of the object and the collection. + +::: tip See also + +See our [JsonMapper](/docs/converters.md#type-mapper) documentation page for details on Type mapper. + +::: \ No newline at end of file diff --git a/packages/common/src/jsonschema/decorators/ignoreProperty.ts b/packages/common/src/jsonschema/decorators/ignoreProperty.ts index 6d11e08b46e..6c8667ed989 100644 --- a/packages/common/src/jsonschema/decorators/ignoreProperty.ts +++ b/packages/common/src/jsonschema/decorators/ignoreProperty.ts @@ -1,7 +1,7 @@ import {Ignore as I} from "@tsed/schema"; /** - * Disable serialization for this property when the Converters service will render the JSON object. + * Ignore the property when JsonMapper serialize the class to a Plain Object JavaScript. * * ::: tip * This decorator is used by the Converters to serialize correctly your model. diff --git a/packages/di/src/decorators/configuration.ts b/packages/di/src/decorators/configuration.ts index b9cd8c4223a..d028f013c02 100644 --- a/packages/di/src/decorators/configuration.ts +++ b/packages/di/src/decorators/configuration.ts @@ -1,9 +1,7 @@ -import {DecoratorParameters, getDecoratorType, StoreSet} from "@tsed/core"; +import {DecoratorParameters, decoratorTypeOf, DecoratorTypes, StoreSet} from "@tsed/core"; import {Inject} from "../decorators/inject"; import {DIConfiguration} from "../services/DIConfiguration"; -export type Configuration = TsED.Configuration & DIConfiguration; - /** * Get or set Configuration on a class. * @@ -11,14 +9,16 @@ export type Configuration = TsED.Configuration & DIConfiguration; */ export function Configuration(configuration: Partial = {}): Function { return (...args: DecoratorParameters) => { - switch (getDecoratorType(args, true)) { - case "class": + switch (decoratorTypeOf(args)) { + case DecoratorTypes.CLASS: StoreSet("configuration", configuration)(args[0]); break; default: - case "parameter.constructor": + case DecoratorTypes.PARAM_CTOR: return Inject(Configuration)(...args); } }; } + +export type Configuration = TsED.Configuration & DIConfiguration; diff --git a/packages/json-mapper/src/utils/serialize.ts b/packages/json-mapper/src/utils/serialize.ts index 840b387f4cb..82561cda2dd 100644 --- a/packages/json-mapper/src/utils/serialize.ts +++ b/packages/json-mapper/src/utils/serialize.ts @@ -37,7 +37,6 @@ export function classToPlainObject(obj: any, options: JsonSerializerOptions { const schema = propStore.schema; - if (alterIgnore(schema, {useAlias, ...props, self: obj})) { return newObj; } diff --git a/packages/schema/src/decorators/common/ignore.ts b/packages/schema/src/decorators/common/ignore.ts index d2e08ae9837..52e8b3fb815 100644 --- a/packages/schema/src/decorators/common/ignore.ts +++ b/packages/schema/src/decorators/common/ignore.ts @@ -2,11 +2,7 @@ import {IgnoreCallback} from "../../interfaces"; import {JsonEntityFn} from "./jsonEntityFn"; /** - * Disable serialization for this property when the Converters service will render the JSON object. - * - * ::: tip - * This decorator is used by the Converters to serialize correctly your model. - * ::: + * Ignore the property when JsonMapper serialize the class to a Plain Object JavaScript. * * ::: warning * Swagger will not generate documentation for the ignored property.