Skip to content

Commit

Permalink
fix(oas): handling header parameters options
Browse files Browse the repository at this point in the history
- exception on `collectionType` `multi` on oas2 path and header params

fixes #120
  • Loading branch information
pmstss committed Feb 21, 2022
1 parent b21b34d commit b0ac0ff
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 41 deletions.
14 changes: 13 additions & 1 deletion packages/oas/src/converter/parts/Oas2ValueSerializer.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import { ConvertError } from '../../errors';
import { isObject, Flattener } from '../../utils';
import { OpenAPIV2 } from '@har-sdk/core';

export class Oas2ValueSerializer {
private readonly flattener = new Flattener();

public serialize(param: OpenAPIV2.Parameter, value: unknown): unknown {
public serialize(
param: OpenAPIV2.Parameter,
value: unknown,
jsonPointer: string
): unknown {
const style = param.collectionFormat;
const explode = param.collectionFormat === 'multi';

if (explode && param.in !== 'formData' && param.in !== 'query') {
throw new ConvertError(
'Collection format `multi` is allowed only for `formData` and `query` parameters',
jsonPointer
);
}

if (explode) {
return value;
}
Expand Down
12 changes: 8 additions & 4 deletions packages/oas/src/converter/parts/headers/HeadersConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { filterLocationParams, getParameters } from '../../../utils';
import { Sampler } from '../Sampler';
import { SubConverter } from '../../SubConverter';
import { Header, OpenAPI, OpenAPIV2, OpenAPIV3 } from '@har-sdk/core';
import jsonPointer from 'json-pointer';

type SecurityRequirementObject =
| OpenAPIV2.SecurityRequirementObject
Expand All @@ -28,7 +29,8 @@ export abstract class HeadersConverter<T extends OpenAPI.Document>

protected abstract convertHeaderParam(
param: ParameterObject,
paramValue: unknown
paramValue: unknown,
paramJsonPointer: string
): Header;

protected abstract getSecuritySchemes():
Expand Down Expand Up @@ -103,18 +105,20 @@ export abstract class HeadersConverter<T extends OpenAPI.Document>
const tokens = ['paths', path, method];

return filterLocationParams(params, 'header').map((param) => {
const idx = params.indexOf(param);
const value = this.sampler.sampleParam(param, {
spec: this.spec,
tokens,
idx: params.indexOf(param)
idx,
spec: this.spec
});

return this.convertHeaderParam(
{
...param,
name: param.name.toLowerCase()
},
value
value,
jsonPointer.compile([...tokens, 'parameters', idx.toString(10)])
);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,16 @@ export class Oas2HeadersConverter extends HeadersConverter<OpenAPIV2.Document> {

protected convertHeaderParam(
param: OpenAPIV2.Parameter,
paramValue: unknown
paramValue: unknown,
jsonPointer: string
): Header {
return {
name: param.name,
value: this.oas2ValueSerializer.serialize(param, paramValue) as string
value: this.oas2ValueSerializer.serialize(
param,
paramValue,
jsonPointer
) as string
};
}

Expand Down
15 changes: 9 additions & 6 deletions packages/oas/src/converter/parts/path/Oas2PathConverter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Sampler } from '../Sampler';
import { Oas2ValueSerializer } from '../Oas2ValueSerializer';
import { PathConverter } from './PathConverter';
import { PathConverter, PathParam } from './PathConverter';
import { OpenAPIV2 } from '@har-sdk/core';

export class Oas2PathConverter extends PathConverter<OpenAPIV2.Parameter> {
Expand All @@ -12,15 +12,18 @@ export class Oas2PathConverter extends PathConverter<OpenAPIV2.Parameter> {

protected parsePath(
path: string,
pathParams: OpenAPIV2.Parameter[],
values: any[]
pathParams: PathParam<OpenAPIV2.Parameter>[]
): string {
return encodeURI(
pathParams.reduce(
(res, param, idx) =>
(res, pathParam) =>
res.replace(
`{${param.name}}`,
this.oas2ValueSerializer.serialize(param, values[idx]) as string
`{${pathParam.param.name}}`,
this.oas2ValueSerializer.serialize(
pathParam.param,
pathParam.value,
pathParam.jsonPointer
) as string
),
path
)
Expand Down
19 changes: 9 additions & 10 deletions packages/oas/src/converter/parts/path/Oas3PathConverter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ParameterObject } from '../../../types';
import { Sampler } from '../Sampler';
import { UriTemplator } from '../UriTemplator';
import { PathConverter } from './PathConverter';
import { PathConverter, PathParam } from './PathConverter';
import { OpenAPIV3 } from '@har-sdk/core';

export class Oas3PathConverter extends PathConverter<OpenAPIV3.ParameterObject> {
Expand All @@ -12,22 +12,21 @@ export class Oas3PathConverter extends PathConverter<OpenAPIV3.ParameterObject>
}

protected parsePath(
input: string,
params: OpenAPIV3.ParameterObject[],
values: any[]
path: string,
pathParams: PathParam<OpenAPIV3.ParameterObject>[]
): string {
const pathTemplateStr = params.reduce(
(res, param) =>
const pathTemplateStr = pathParams.reduce(
(res, { param }) =>
res.replace(`{${param.name}}`, this.getOas3PathParamUriTemplate(param)),
input
path
);

return this.uriTemplator.substitute(
pathTemplateStr,
params.reduce(
(res, param, idx) => ({
pathParams.reduce(
(res, pathParam) => ({
...res,
[param.name]: values[idx]
[pathParam.param.name]: pathParam.value
}),
{}
)
Expand Down
39 changes: 27 additions & 12 deletions packages/oas/src/converter/parts/path/PathConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@ import { ParameterObject } from '../../../types';
import { getParameters, filterLocationParams } from '../../../utils';
import { Sampler } from '../Sampler';
import { SubConverter } from '../../SubConverter';
import jsonPointer from 'json-pointer';
import { OpenAPI } from '@har-sdk/core';

export interface PathParam<T> {
readonly param: T;
readonly value: unknown;
readonly jsonPointer: string;
}

export abstract class PathConverter<T extends ParameterObject>
implements SubConverter<string>
{
Expand All @@ -12,25 +19,33 @@ export abstract class PathConverter<T extends ParameterObject>
private readonly sampler: Sampler
) {}

protected abstract parsePath(
path: string,
pathParams: T[],
paramValues: any[]
): string;
protected abstract parsePath(path: string, params: PathParam<T>[]): string;

public convert(path: string, method: string): string {
const params: ParameterObject[] = getParameters(this.spec, path, method);
const pathParams = filterLocationParams(params, 'path');

const tokens = ['paths', path, method];
const sampledParamValues = pathParams.map((param) =>
this.sampler.sampleParam(param, {
tokens,
spec: this.spec,
idx: params.indexOf(param)

return this.parsePath(
path,
pathParams.map((param) => {
const idx = params.indexOf(param);

return {
param: param as T,
jsonPointer: jsonPointer.compile([
...tokens,
'parameters',
idx.toString(10)
]),
value: this.sampler.sampleParam(param, {
tokens,
idx,
spec: this.spec
})
};
})
);

return this.parsePath(path, pathParams as T[], sampledParamValues);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ export class Oas2QueryStringConverter extends QueryStringConverter<OpenAPIV2.Par

protected convertQueryParam(
param: OpenAPIV2.Parameter,
paramValue: unknown
paramValue: unknown,
paramJsonPointer: string
): QueryString[] {
const { name } = param;
const value = this.oas2ValueSerializer.serialize(
param as OpenAPIV2.Parameter,
paramValue
paramValue,
paramJsonPointer
);

let values: QueryString[];
Expand Down
15 changes: 11 additions & 4 deletions packages/oas/src/converter/parts/query/QueryStringConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ParameterObject } from '../../../types';
import { getParameters, filterLocationParams } from '../../../utils';
import { Sampler } from '../Sampler';
import { SubConverter } from '../../SubConverter';
import jsonPointer from 'json-pointer';
import { OpenAPI, QueryString } from '@har-sdk/core';

export abstract class QueryStringConverter<T extends ParameterObject>
Expand All @@ -14,21 +15,27 @@ export abstract class QueryStringConverter<T extends ParameterObject>

protected abstract convertQueryParam(
param: T,
paramValue: unknown
paramValue: unknown,
paramJsonPointer: string
): QueryString[];

public convert(path: string, method: string): QueryString[] {
const tokens = ['paths', path, method];
const params: ParameterObject[] = getParameters(this.spec, path, method);

return filterLocationParams(params, 'query').flatMap((param) => {
const idx = params.indexOf(param);
const value = this.sampler.sampleParam(param, {
tokens,
spec: this.spec,
idx: params.indexOf(param)
idx,
spec: this.spec
});

return this.convertQueryParam(param as T, value);
return this.convertQueryParam(
param as T,
value,
jsonPointer.compile([...tokens, 'parameters', idx.toString(10)])
);
});
}
}
8 changes: 8 additions & 0 deletions packages/oas/tests/DefaultConverter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,18 @@ describe('DefaultConverter', () => {
input: 'convert-error-on-header.swagger.yaml',
expected: '/paths/~1store~1order~1{orderId}/put/parameters/2'
},
{
input: 'convert-error-on-header-multi.swagger.yaml',
expected: '/paths/~1headers~1{p}/get/parameters/1'
},
{
input: 'convert-error-on-path.swagger.yaml',
expected: '/paths/~1store~1order~1{orderId}/put/parameters/0'
},
{
input: 'convert-error-on-path-multi.swagger.yaml',
expected: '/paths/~1headers~1{p}/get/parameters/0'
},
{
input: 'convert-error-on-query.swagger.yaml',
expected: '/paths/~1store~1order~1{orderId}/put/parameters/1'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
swagger: '2.0'
info:
title: Header Parameters Test
version: 1.0.0
host: petstore.swagger.io
basePath: /v1
schemes:
- http
paths:
/headers/{p}:
get:
parameters:
- name: p
in: path
required: true
type: string
- name: X-Array-Multi
in: header
required: true
collectionFormat: multi
type: array
minItems: 2
items:
type: string
responses:
'200':
description: OK
examples:
application/json:
ok: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
swagger: '2.0'
info:
title: Path Parameters Test
version: 1.0.0
host: petstore.swagger.io
basePath: /v1
schemes:
- http
paths:
/headers/{p}:
get:
parameters:
- name: p
in: path
required: true
collectionFormat: multi
type: array
minItems: 2
items:
type: string
responses:
'200':
description: OK
examples:
application/json:
ok: true

0 comments on commit b0ac0ff

Please sign in to comment.