Swagger: Unwanted isArray property in @modelPropertyApi

Created on 4 Oct 2018  路  11Comments  路  Source: nestjs/swagger

I'm submitting a...


[ ] Regression 
[X] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

In the decorator _@modelPropertyApi_, if I specify the _type_ property, also _isArray_ property will be specified.
screenshot 2018-10-04 at 11 44 23

The issue is located in _getTypeIsArrayTuple_ helper function

Expected behavior

The property, should not have additional properties, in this case _isArray_

bug next

Most helpful comment

@nartc When do you think it will be merged ? Thank you.

All 11 comments

Can you show the piece of code that renders this Spec? What Decorator did you use?

@ApiModelProperty({
    type: 'integer',
    example: 1,
  })
  @IsInt()
  public typeId: number;

The result is

      parameters:
        - name: caseTypeId
          in: path
          required: true
          type: integer
          isArray: false

IsArray is not valid for this property, so swagger editor give me an error.

149 will fix the issue if merged :)

@ApiModelProperty({ required: true, type: String })

@nartc When do you think it will be merged ? Thank you.

I am facing same issue with the following:

@ApiImplicitBody({
name: 'body',
type: Object,
description: 'some lovely description'
})

The PR is open since a long time, will it ever me merged?

It's a really annoying bug... I copied all needed things into one file if anybody can't continue working like us:

import { isNil, isUndefined, negate, pickBy } from "lodash";
import * as _ from "underscore";

// TODO: Remove this file when https://github.com/nestjs/swagger/issues/147 is finally merged

const initialMetadata = {
  name: "",
  required: true,
  type: String
};

const DECORATORS_PREFIX = "swagger";

const DECORATORS = {
  API_PARAMETERS: `${DECORATORS_PREFIX}/apiParameters`
};

const createParamDecorator = (metadata, initial) => {
  return (target, key, descriptor: PropertyDescriptor) => {
    const parameters =
      Reflect.getMetadata(DECORATORS.API_PARAMETERS, descriptor.value) || [];
    Reflect.defineMetadata(
      DECORATORS.API_PARAMETERS,
      [
        ...parameters,
        {
          ...initial,
          ...pickBy(metadata, negate(isUndefined))
        }
      ],
      descriptor.value
    );
    return descriptor;
  };
};

const getTypeIsArrayTuple = (
  input: Function | [Function] | undefined,
  isArrayFlag: boolean
): [Function | undefined, boolean] => {
  if (!input) {
    return [input as undefined, isArrayFlag];
  }
  if (isArrayFlag) {
    return [input as Function, isArrayFlag];
  }
  const isInputArray = _.isArray(input);
  const type = isInputArray ? input[0] : input;
  return [type, isInputArray];
};

export const FixedApiImplicitBody = (metadata: {
  name: string;
  type: any;
  description?: string;
  required?: boolean;
  isArray?: boolean;
}): MethodDecorator => {
  const [type, isArray] = getTypeIsArrayTuple(metadata.type, metadata.isArray);
  const param: any = {
    name: isNil(metadata.name) ? initialMetadata.name : metadata.name,
    in: "body",
    description: metadata.description,
    required: metadata.required,
    type
  };
  if (isArray) {
    param.isArray = isArray;
  }
  return createParamDecorator(param, initialMetadata);
};

Got a workaround for this if you are trying to generate a valid swagger.json:

function transformObjectsDeep(data: any, fn: (item: any) => any) {
  return isArray(data)
    ? data.map((item) => transformObjectsDeep(item, fn))
    : isObject(data)
      ? fn(data)
      : data;
}

const omitKeysDeepBy = (...matchers: Array<Function>) => (data: any) =>
  transform(data as any, (accum, value: any, key: string) => {
    if (!matchers.some((matcher) => matcher(key, value, data))) {
      accum[key] = transformObjectsDeep(value, omitKeysDeepBy(...matchers));
    }
  }, {});

async function main() {
  const app = await NestFactory.create(ApplicationModule);

  const options = new DocumentBuilder()
    .setTitle('My API')
    .setVersion('1.0.0')
    .build();

  const document = SwaggerModule.createDocument(app, options);
  const omitMatchingKeys = omitKeysDeepBy((key: string) => key === 'isArray');
  const data = transformObjectsDeep(document, omitMatchingKeys);

  mkdirSync('./dist', { recursive: true });
  writeFileSync('./dist/swagger.json', JSON.stringify(data, null, 2), 'utf8');

  app.close();
}

Fixed in the next version (to install run npm i @nestjs/swagger@next). Note: remember to update @nestjs/common, @nestjs/core and typescript as well to ensure that you're using the latest versions.

Steps to migrate: https://github.com/nestjs/swagger/pull/355#issuecomment-547925879

4.0.0 has been published

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dennisameling picture dennisameling  路  4Comments

itslenny picture itslenny  路  3Comments

Fiorello picture Fiorello  路  5Comments

kalaivanan-muthusamy picture kalaivanan-muthusamy  路  4Comments

yuval-hazaz picture yuval-hazaz  路  3Comments