@tsed/schema
Version:
JsonSchema module for Ts.ED Framework
512 lines (511 loc) • 9.39 kB
JavaScript
import { JsonFormatTypes } from "../../domain/JsonFormatTypes.js";
import { withErrorMsg } from "../../utils/withErrorMsg.js";
import { JsonEntityFn } from "./jsonEntityFn.js";
/**
* Applies a format validation to string properties using JSON Schema's `format` keyword.
*
* The `@Format()` decorator validates string values against common formats like email,
* URI, date-time, and IP addresses. This provides semantic validation beyond just checking
* the string type.
*
* ### Supported Formats
*
* - **date**: Full-date according to RFC3339 (`2024-01-15`)
* - **time**: Time with optional time-zone (`14:30:00`, `14:30:00+02:00`)
* - **date-time**: Date-time from RFC3339 (time-zone mandatory: `2024-01-15T14:30:00Z`)
* - **uri**: Full URI with optional protocol (`https://example.com/path`)
* - **url**: Valid URL (stricter than uri)
* - **email**: Email address (`user@example.com`)
* - **hostname**: Host name according to RFC1034 (`example.com`)
* - **ipv4**: IPv4 address (`192.168.1.1`)
* - **ipv6**: IPv6 address (`2001:0db8:85a3::8a2e:0370:7334`)
* - **regex**: Valid regular expression pattern
*
* ### Basic Usage
*
* ```typescript
* class ContactModel {
* @Format("email")
* email: string;
*
* @Format("uri")
* website: string;
*
* @Format("ipv4")
* serverIp: string;
* }
* ```
*
* ### With Arrays
*
* ```typescript
* class ServerConfig {
* @Format("email")
* @CollectionOf(String)
* adminEmails: string[];
* // Each email must be valid
* }
* ```
*
* ### Date/Time Formats
*
* ```typescript
* class EventModel {
* @Format("date")
* eventDate: string; // "2024-12-25"
*
* @Format("time")
* startTime: string; // "14:30:00"
*
* @Format("date-time")
* createdAt: string; // "2024-01-15T14:30:00Z"
* }
* ```
*
* ### Convenience Decorators
*
* Ts.ED provides convenience decorators that use `@Format()` internally:
*
* - `@Email()` - Equivalent to `@Format("email")`
* - `@DateTime()` - Equivalent to `@Format("date-time")`
* - `@DateFormat()` - Equivalent to `@Format("date")`
* - `@TimeFormat()` - Equivalent to `@Format("time")`
* - `@Uri()` - Equivalent to `@Format("uri")`
* - `@Url()` - Equivalent to `@Format("url")`
*
* ### Use Cases
*
* - **Data Integrity**: Ensure strings conform to expected formats
* - **API Validation**: Validate input data at API boundaries
* - **Database Constraints**: Match database column format requirements
* - **Standards Compliance**: Ensure RFC compliance for dates, emails, URIs
*
* ### Validation Examples
*
* ```typescript
* @Format("email")
* email: string;
*
* // Valid:
* "user@example.com"
* "jane.doe+tag@company.co.uk"
*
* // Invalid:
* "not-an-email"
* "missing@domain"
* "@example.com"
* ```
*
* ### Important Notes
*
* - Format validation depends on the validator implementation (AJV, etc.)
* - Some formats may require additional validator plugins
* - Format is primarily for strings; use on other types may be ignored
* - Can be combined with other string validators (MinLength, Pattern, etc.)
*
* @param format - The format keyword to apply (from JsonFormatTypes enum)
*
* @decorator
* @validation
* @public
*/
export const Format = withErrorMsg("format", (format) => {
return JsonEntityFn((store) => {
store.itemSchema.format(format);
});
});
/**
* Apply an email validation on property.
*
* ::: warning
* For v6 user, use @@Email@@ from @tsed/schema instead of @tsed/platform-http.
* :::
*
* ## Example
* ### With primitive type
*
* ```typescript
* class Model {
* @Email()
* property: string;
* }
* ```
*
* Will produce:
*
* ```json
* {
* "type": "object",
* "properties": {
* "property": {
* "type": "string",
* "format": "email"
* }
* }
* }
* ```
*
* ### With array type
*
* ```typescript
* class Model {
* @Email()
* @CollectionOf(String)
* property: string[];
* }
* ```
*
* Will produce:
*
* ```json
* {
* "type": "object",
* "properties": {
* "property": {
* "type": "array",
* "items": {
* "type": "string",
* "format": "email"
* }
* }
* }
* }
* ```
*
* @returns {Function}
* @decorator
* @validation
* @schema
* @swagger
* @input
* @ajv-errors
*/
export const Email = withErrorMsg("format", () => {
return Format(JsonFormatTypes.EMAIL);
});
/**
* Apply a date-time validation on property.
*
* ## Example
* ### With primitive type
*
* ```typescript
* class Model {
* @DateTime()
* property: string;
* }
* ```
*
* Will produce:
*
* ```json
* {
* "type": "object",
* "properties": {
* "property": {
* "type": "string",
* "format": "date-time"
* }
* }
* }
* ```
*
* ### With array type
*
* ```typescript
* class Model {
* @DateTime()
* @CollectionOf(String)
* property: string[];
* }
* ```
*
* Will produce:
*
* ```json
* {
* "type": "object",
* "properties": {
* "property": {
* "type": "array",
* "items": {
* "type": "string",
* "format": "date-time"
* }
* }
* }
* }
* ```
*
* @returns {Function}
* @decorator
* @validation
* @property
* @parameter
* @schema
* @auto-map The data will be stored on the right place according to the type and collectionType (primitive or collection).
* @ajv-errors
*/
export const DateTime = withErrorMsg("format", () => {
return Format(JsonFormatTypes.DATE_TIME);
});
/**
* Apply a time validation on property.
*
* ## Example
* ### With primitive type
*
* ```typescript
* class Model {
* @Time()
* property: string;
* }
* ```
*
* Will produce:
*
* ```json
* {
* "type": "object",
* "properties": {
* "property": {
* "type": "string",
* "format": "time"
* }
* }
* }
* ```
*
* ### With array type
*
* ```typescript
* class Model {
* @Time()
* @CollectionOf(String)
* property: string[];
* }
* ```
*
* Will produce:
*
* ```json
* {
* "type": "object",
* "properties": {
* "property": {
* "type": "array",
* "items": {
* "type": "string",
* "format": "time"
* }
* }
* }
* }
* ```
*
* @returns {Function}
* @decorator
* @validation
* @property
* @parameter
* @schema
* @ajv-errors
*/
export const DateFormat = withErrorMsg("format", () => {
return Format(JsonFormatTypes.DATE);
});
/**
* Apply a time validation on property.
*
* ## Example
* ### With primitive type
*
* ```typescript
* class Model {
* @TimeFormat()
* property: string;
* }
* ```
*
* Will produce:
*
* ```json
* {
* "type": "object",
* "properties": {
* "property": {
* "type": "string",
* "format": "time"
* }
* }
* }
* ```
*
* ### With array type
*
* ```typescript
* class Model {
* @TimeFormat()
* @CollectionOf(String)
* property: string[];
* }
* ```
*
* Will produce:
*
* ```json
* {
* "type": "object",
* "properties": {
* "property": {
* "type": "array",
* "items": {
* "type": "string",
* "format": "time"
* }
* }
* }
* }
* ```
*
* @returns {Function}
* @decorator
* @validation
* @property
* @parameter
* @schema
* @ajv-errors
*/
export const TimeFormat = withErrorMsg("format", () => {
return Format(JsonFormatTypes.TIME);
});
/**
* Apply a uri validation on property.
*
* ## Example
* ### With primitive type
*
* ```typescript
* class Model {
* @Uri()
* property: string;
* }
* ```
*
* Will produce:
*
* ```json
* {
* "type": "object",
* "properties": {
* "property": {
* "type": "string",
* "format": "uri"
* }
* }
* }
* ```
*
* ### With array type
*
* ```typescript
* class Model {
* @Uri()
* @CollectionOf(String)
* property: string[];
* }
* ```
*
* Will produce:
*
* ```json
* {
* "type": "object",
* "properties": {
* "property": {
* "type": "array",
* "items": {
* "type": "string",
* "format": "uri"
* }
* }
* }
* }
* ```
*
* @returns {Function}
* @decorator
* @validation
* @property
* @parameter
* @schema
* @ajv-errors
*/
export const Uri = withErrorMsg("format", () => {
return Format(JsonFormatTypes.URI);
});
/**
* Apply a url validation on property.
*
* ## Example
* ### With primitive type
*
* ```typescript
* class Model {
* @Url()
* property: string;
* }
* ```
*
* Will produce:
*
* ```json
* {
* "type": "object",
* "properties": {
* "property": {
* "type": "string",
* "format": "url"
* }
* }
* }
* ```
*
* ### With array type
*
* ```typescript
* class Model {
* @Url()
* @CollectionOf(String)
* property: string[];
* }
* ```
*
* Will produce:
*
* ```json
* {
* "type": "object",
* "properties": {
* "property": {
* "type": "array",
* "items": {
* "type": "string",
* "format": "url"
* }
* }
* }
* }
* ```
*
* @returns {Function}
* @decorator
* @validation
* @property
* @parameter
* @schema
* @ajv-errors
*/
export const Url = withErrorMsg("format", () => {
return Format(JsonFormatTypes.URL);
});