diff --git a/README.md b/README.md index cb0cb397..1a9fab4a 100644 --- a/README.md +++ b/README.md @@ -329,6 +329,42 @@ enum EnumWithStrings { ``` +### Nullable in OpenAPI v2 +In the OpenAPI v3 spec you can create properties that can be NULL, by providing a `nullable: true` in your schema. +However, the v2 spec does not allow you to do this. You can use the unofficial `x-nullable` in your specification +to generate nullable properties in OpenApi v2. + +```json +{ + "ModelWithNullableString": { + "required": ["requiredProp"], + "description": "This is a model with one string property", + "type": "object", + "properties": { + "prop": { + "description": "This is a simple string property", + "type": "string", + "x-nullable": true + }, + "requiredProp": { + "description": "This is a simple string property", + "type": "string", + "x-nullable": true + } + } + } +} +``` + +Generated code: +```typescript +interface ModelWithNullableString { + prop?: string | null, + requiredProp: string | null, +} +``` + + ### Authorization The OpenAPI generator supports Bearer Token authorization. In order to enable the sending of tokens in each request you can set the token using the global OpenAPI configuration: diff --git a/src/index.spec.ts b/src/index.spec.ts index 29251d33..d1170357 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -3,8 +3,8 @@ import * as OpenAPI from './index'; describe('index', () => { it('parses v2 without issues', async () => { await OpenAPI.generate({ - input: './test/spec/v3.json', - output: './generated/v3/', + input: './test/spec/v2.json', + output: './generated/v2/', write: false, }); }); diff --git a/src/openApi/v2/interfaces/Extensions/WithEnumExtension.d.ts b/src/openApi/v2/interfaces/Extensions/WithEnumExtension.d.ts index c4ebbd41..0d6ead78 100644 --- a/src/openApi/v2/interfaces/Extensions/WithEnumExtension.d.ts +++ b/src/openApi/v2/interfaces/Extensions/WithEnumExtension.d.ts @@ -1,6 +1,3 @@ -/** - * Supported extension for enums - */ export interface WithEnumExtension { 'x-enum-varnames'?: string[]; 'x-enum-descriptions'?: string[]; diff --git a/src/openApi/v2/interfaces/Extensions/WithNullableExtension.d.ts b/src/openApi/v2/interfaces/Extensions/WithNullableExtension.d.ts new file mode 100644 index 00000000..ed2632ff --- /dev/null +++ b/src/openApi/v2/interfaces/Extensions/WithNullableExtension.d.ts @@ -0,0 +1,3 @@ +export interface WithNullableExtension { + 'x-nullable'?: boolean; +} diff --git a/src/openApi/v2/interfaces/OpenApiSchema.d.ts b/src/openApi/v2/interfaces/OpenApiSchema.d.ts index abba5fce..4ac0f559 100644 --- a/src/openApi/v2/interfaces/OpenApiSchema.d.ts +++ b/src/openApi/v2/interfaces/OpenApiSchema.d.ts @@ -1,5 +1,6 @@ import type { Dictionary } from '../../../utils/types'; import type { WithEnumExtension } from './Extensions/WithEnumExtension'; +import type { WithNullableExtension } from './Extensions/WithNullableExtension'; import type { OpenApiExternalDocs } from './OpenApiExternalDocs'; import type { OpenApiReference } from './OpenApiReference'; import type { OpenApiXml } from './OpenApiXml'; @@ -7,7 +8,7 @@ import type { OpenApiXml } from './OpenApiXml'; /** * https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#schemaObject */ -export interface OpenApiSchema extends OpenApiReference, WithEnumExtension { +export interface OpenApiSchema extends OpenApiReference, WithEnumExtension, WithNullableExtension { title?: string; description?: string; default?: any; diff --git a/src/openApi/v2/parser/getModelProperties.ts b/src/openApi/v2/parser/getModelProperties.ts index 7623814e..cb824aba 100644 --- a/src/openApi/v2/parser/getModelProperties.ts +++ b/src/openApi/v2/parser/getModelProperties.ts @@ -26,7 +26,7 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema, isDefinition: false, isReadOnly: property.readOnly === true, isRequired: propertyRequired === true, - isNullable: false, + isNullable: property['x-nullable'] === true, format: property.format, maximum: property.maximum, exclusiveMaximum: property.exclusiveMaximum, @@ -60,7 +60,7 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema, isDefinition: false, isReadOnly: property.readOnly === true, isRequired: propertyRequired === true, - isNullable: false, + isNullable: property['x-nullable'] === true, format: property.format, maximum: property.maximum, exclusiveMaximum: property.exclusiveMaximum, @@ -84,6 +84,5 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema, } } } - return models; } diff --git a/src/openApi/v3/interfaces/Extensions/WithEnumExtension.d.ts b/src/openApi/v3/interfaces/Extensions/WithEnumExtension.d.ts index c4ebbd41..0d6ead78 100644 --- a/src/openApi/v3/interfaces/Extensions/WithEnumExtension.d.ts +++ b/src/openApi/v3/interfaces/Extensions/WithEnumExtension.d.ts @@ -1,6 +1,3 @@ -/** - * Supported extension for enums - */ export interface WithEnumExtension { 'x-enum-varnames'?: string[]; 'x-enum-descriptions'?: string[]; diff --git a/test/__snapshots__/index.spec.js.snap b/test/__snapshots__/index.spec.js.snap index 7f3ade70..c12e9b75 100644 --- a/test/__snapshots__/index.spec.js.snap +++ b/test/__snapshots__/index.spec.js.snap @@ -301,6 +301,7 @@ export type { ModelWithInteger } from './models/ModelWithInteger'; export type { ModelWithLink } from './models/ModelWithLink'; export type { ModelWithNestedEnums } from './models/ModelWithNestedEnums'; export type { ModelWithNestedProperties } from './models/ModelWithNestedProperties'; +export type { ModelWithNullableString } from './models/ModelWithNullableString'; export type { ModelWithOrderedProperties } from './models/ModelWithOrderedProperties'; export type { ModelWithPattern } from './models/ModelWithPattern'; export type { ModelWithProperties } from './models/ModelWithProperties'; @@ -343,6 +344,7 @@ export { $ModelWithInteger } from './schemas/$ModelWithInteger'; export { $ModelWithLink } from './schemas/$ModelWithLink'; export { $ModelWithNestedEnums } from './schemas/$ModelWithNestedEnums'; export { $ModelWithNestedProperties } from './schemas/$ModelWithNestedProperties'; +export { $ModelWithNullableString } from './schemas/$ModelWithNullableString'; export { $ModelWithOrderedProperties } from './schemas/$ModelWithOrderedProperties'; export { $ModelWithPattern } from './schemas/$ModelWithPattern'; export { $ModelWithProperties } from './schemas/$ModelWithProperties'; @@ -833,6 +835,26 @@ export interface ModelWithNestedProperties { " `; +exports[`v2 should generate: ./test/generated/v2/models/ModelWithNullableString.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +/** + * This is a model with one string property + */ +export interface ModelWithNullableString { + /** + * This is a simple string property + */ + nullableProp?: string | null; + /** + * This is a simple string property + */ + nullableRequiredProp: string | null; +} +" +`; + exports[`v2 should generate: ./test/generated/v2/models/ModelWithOrderedProperties.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -1362,6 +1384,25 @@ export const $ModelWithNestedProperties = { };" `; +exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithNullableString.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $ModelWithNullableString = { + properties: { + nullableProp: { + type: 'string', + isNullable: true, + }, + nullableRequiredProp: { + type: 'string', + isRequired: true, + isNullable: true, + }, + }, +};" +`; + exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithOrderedProperties.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ diff --git a/test/spec/v2.json b/test/spec/v2.json index e4b9b579..ccd3d6a0 100644 --- a/test/spec/v2.json +++ b/test/spec/v2.json @@ -858,6 +858,25 @@ } } }, + "ModelWithNullableString": { + "description": "This is a model with one string property", + "type": "object", + "required": [ + "nullableRequiredProp" + ], + "properties": { + "nullableProp": { + "description": "This is a simple string property", + "type": "string", + "x-nullable": true + }, + "nullableRequiredProp": { + "description": "This is a simple string property", + "type": "string", + "x-nullable": true + } + } + }, "ModelWithEnum": { "description": "This is a model with one enum", "type": "object",