Skip to content

Commit

Permalink
Support headers (#133)
Browse files Browse the repository at this point in the history
partially closes #57
  • Loading branch information
Lonelind authored Dec 24, 2020
1 parent 7448720 commit 1b0c947
Show file tree
Hide file tree
Showing 9 changed files with 206 additions and 14 deletions.
53 changes: 46 additions & 7 deletions src/language/typescript/2.0/serializers/operation-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
ArrayParameterObjectCollectionFormat,
BodyParameterObject,
FormDataParameterObject,
HeaderParameterObject,
ParameterObject,
ParameterObjectCodec,
PathParameterObject,
Expand Down Expand Up @@ -53,13 +52,18 @@ import {
} from '../../common/data/serialized-fragment';
import { sequenceOptionEither } from '../../../../utils/option';
import { identity } from 'fp-ts/lib/function';
import {
fromSerializedHeaderParameter,
getSerializedHeaderParameterType,
SerializedHeaderParameter,
} from '../../common/data/serialized-header-parameters';

interface Parameters {
readonly pathParameters: PathParameterObject[];
readonly serializedPathParameters: SerializedPathParameter[];
readonly serializedQueryParameter: Option<SerializedType>;
readonly serializedBodyParameter: Option<SerializedType>;
readonly headerParameters: HeaderParameterObject[];
readonly serializedHeadersParameter: Option<SerializedType>;
readonly formDataParameters: FormDataParameterObject[];
readonly queryString: Option<SerializedFragment>;
}
Expand All @@ -79,7 +83,7 @@ const getParameters = combineReader(
const serializedPathParameters: SerializedPathParameter[] = [];
const serializedQueryParameters: SerializedType[] = [];
const bodyParameters: BodyParameterObject[] = [];
const headerParameters: HeaderParameterObject[] = [];
const serializedHeaderParameters: SerializedHeaderParameter[] = [];
const formDataParameters: FormDataParameterObject[] = [];
const queryStringFragments: SerializedFragment[] = [];

Expand Down Expand Up @@ -129,7 +133,13 @@ const getParameters = combineReader(
break;
}
case 'header': {
headerParameters.push(resolved.right);
const serializedParameter = pipe(
serialized.right,
fromSerializedHeaderParameter(resolved.right.name),
getSerializedHeaderParameterType,
);

serializedHeaderParameters.push(serializedParameter);
break;
}
case 'formData': {
Expand Down Expand Up @@ -195,6 +205,16 @@ const getParameters = combineReader(
sequenceOptionEither,
);

const serializedHeadersParameter = pipe(
nonEmptyArray.fromArray(serializedHeaderParameters),
option.map(parameters =>
pipe(
intercalateSerializedTypes(serializedType(';', ',', [], []), parameters),
getSerializedObjectType(),
),
),
);

const queryString = pipe(
nonEmptyArray.fromArray(queryStringFragments),
option.map(queryStringFragments =>
Expand All @@ -215,7 +235,7 @@ const getParameters = combineReader(
serializedPathParameters,
serializedQueryParameter,
serializedBodyParameter,
headerParameters,
serializedHeadersParameter,
formDataParameters,
queryString,
}));
Expand Down Expand Up @@ -258,7 +278,8 @@ export const serializeOperationObject = combineReader(
(parameters, serializedResponses, clientRef) => {
const hasQueryParameters = isSome(parameters.serializedQueryParameter);
const hasBodyParameters = isSome(parameters.serializedBodyParameter);
const hasParameters = hasQueryParameters || hasBodyParameters;
const hasHeaderParameters = isSome(parameters.serializedHeadersParameter);
const hasParameters = hasQueryParameters || hasBodyParameters || hasHeaderParameters;

const bodyType = pipe(
parameters.serializedBodyParameter,
Expand All @@ -282,10 +303,22 @@ export const serializeOperationObject = combineReader(
option.getOrElse(() => ''),
);

const headersType = pipe(
parameters.serializedHeadersParameter,
option.map(headers => `headers: ${headers.type}`),
option.getOrElse(() => ''),
);

const headersIO = pipe(
parameters.serializedHeadersParameter,
option.map(headers => `const headers = ${headers.io}.encode(parameters.headers)`),
option.getOrElse(() => ''),
);

const argsType = concatIf(
hasParameters,
parameters.serializedPathParameters.map(p => p.type),
[`parameters: { ${queryType}${bodyType} }`],
[`parameters: { ${queryType}${bodyType}${headersType} }`],
).join(',');

const type = `
Expand All @@ -303,13 +336,15 @@ export const serializeOperationObject = combineReader(
${operationName}: (${argsIO}) => {
${bodyIO}
${queryIO}
${headersIO}
return e.httpClient.chain(
e.httpClient.request({
url: ${getURL(url, parameters.serializedPathParameters)},
method: '${method}',
${when(hasQueryParameters, 'query,')}
${when(hasBodyParameters, 'body,')}
${when(hasHeaderParameters, 'headers')}
}),
value =>
pipe(
Expand Down Expand Up @@ -342,6 +377,10 @@ export const serializeOperationObject = combineReader(
parameters.queryString,
option.map(p => p.dependencies),
),
pipe(
parameters.serializedHeadersParameter,
option.map(p => p.dependencies),
),
]),
]),
];
Expand Down
51 changes: 49 additions & 2 deletions src/language/typescript/3.0/serializers/operation-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ import {
SerializedFragment,
} from '../../common/data/serialized-fragment';
import { SchemaObjectCodec } from '../../../../schema/3.0/schema-object';
import {
fromSerializedHeaderParameter,
getSerializedHeaderParameterType,
SerializedHeaderParameter,
} from '../../common/data/serialized-header-parameters';

const getOperationName = (pattern: string, operation: OperationObject, method: HTTPMethod): string =>
pipe(
Expand All @@ -61,6 +66,7 @@ interface Parameters {
readonly serializedPathParameters: SerializedPathParameter[];
readonly serializedQueryParameter: Option<SerializedType>;
readonly serializedBodyParameter: Option<SerializedType>;
readonly serializedHeadersParameter: Option<SerializedType>;
readonly serializedQueryString: Option<SerializedFragment>;
}

Expand All @@ -79,6 +85,7 @@ export const getParameters = combineReader(
const serializedQueryParameters: SerializedType[] = [];
let serializedBodyParameter: Option<SerializedType> = none;
const queryStringFragments: SerializedFragment[] = [];
const serializedHeaderParameters: SerializedHeaderParameter[] = [];

// note that PathItem parameters should go after OperationObject parameters because they have lower priority
// this means that OperationObject can override PathItemObject parameters
Expand Down Expand Up @@ -126,6 +133,16 @@ export const getParameters = combineReader(
serializedPathParameters.push(serializedParameter);
break;
}
case 'header': {
const serializedParameter = pipe(
serialized.right,
fromSerializedHeaderParameter(resolved.right.name),
getSerializedHeaderParameterType,
);

serializedHeaderParameters.push(serializedParameter);
break;
}
case 'query': {
const serializedParameter = getSerializedOptionalType(required, serialized.right);
const schema = getParameterObjectSchema(resolved.right);
Expand Down Expand Up @@ -217,10 +234,21 @@ export const getParameters = combineReader(
),
);

const serializedHeadersParameter = pipe(
nonEmptyArray.fromArray(serializedHeaderParameters),
option.map(parameters =>
pipe(
intercalateSerializedTypes(serializedType(';', ',', [], []), parameters),
getSerializedObjectType(),
),
),
);

return right({
pathParameters,
serializedPathParameters,
serializedQueryParameter,
serializedHeadersParameter,
serializedBodyParameter,
serializedQueryString,
});
Expand Down Expand Up @@ -254,7 +282,8 @@ export const serializeOperationObject = combineReader(
(parameters, serializedResponses, clientRef) => {
const hasQueryParameters = isSome(parameters.serializedQueryParameter);
const hasBodyParameter = isSome(parameters.serializedBodyParameter);
const hasParameters = hasQueryParameters || hasBodyParameter;
const hasHeaderParameters = isSome(parameters.serializedHeadersParameter);
const hasParameters = hasQueryParameters || hasBodyParameter || hasHeaderParameters;

const bodyType = pipe(
parameters.serializedBodyParameter,
Expand All @@ -278,10 +307,22 @@ export const serializeOperationObject = combineReader(
option.getOrElse(() => ''),
);

const headersType = pipe(
parameters.serializedHeadersParameter,
option.map(headers => `headers: ${headers.type}`),
option.getOrElse(() => ''),
);

const headersIO = pipe(
parameters.serializedHeadersParameter,
option.map(headers => `const headers = ${headers.io}.encode(parameters.headers)`),
option.getOrElse(() => ''),
);

const argsType = concatIf(
hasParameters,
parameters.serializedPathParameters.map(p => p.type),
[`parameters: { ${queryType}${bodyType} }`],
[`parameters: { ${queryType}${bodyType}${headersType} }`],
).join(',');

const type = `
Expand All @@ -299,13 +340,15 @@ export const serializeOperationObject = combineReader(
${operationName}: (${argsIO}) => {
${bodyIO}
${queryIO}
${headersIO}
return e.httpClient.chain(
e.httpClient.request({
url: ${getURL(pattern, parameters.serializedPathParameters)},
method: '${method}',
${when(hasQueryParameters, 'query,')}
${when(hasBodyParameter, 'body,')}
${when(hasHeaderParameters, 'headers')}
}),
value =>
pipe(
Expand Down Expand Up @@ -338,6 +381,10 @@ export const serializeOperationObject = combineReader(
parameters.serializedQueryString,
option.map(p => p.dependencies),
),
pipe(
parameters.serializedHeadersParameter,
option.map(p => p.dependencies),
),
]),
]),
];
Expand Down
1 change: 1 addition & 0 deletions src/language/typescript/common/bundled/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const client = `
readonly url: string;
readonly query?: string;
readonly body?: unknown;
readonly headers?: Record<string, unknown>;
}
export interface HTTPClient<F> extends MonadThrow<F> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Ref, uniqRefs } from '../../../../utils/ref';
import { getTypeName } from '../utils';
import { serializedDependency, SerializedDependency, uniqSerializedDependencies } from './serialized-dependency';
import { SerializedParameter } from './serialized-parameter';

export interface SerializedHeaderParameter extends SerializedParameter {
readonly name: string;
}

export const serializedHeaderParameter = (
name: string,
type: string,
io: string,
isRequired: boolean,
dependencies: SerializedDependency[],
refs: Ref[],
): SerializedHeaderParameter => ({
name,
type,
io,
isRequired,
dependencies: uniqSerializedDependencies(dependencies),
refs: uniqRefs(refs),
});

export const fromSerializedHeaderParameter = (name: string) => (
serialized: SerializedParameter,
): SerializedHeaderParameter => ({
...serialized,
name,
});

export const getSerializedHeaderParameterType = (serialized: SerializedHeaderParameter): SerializedHeaderParameter => {
const name = getTypeName(serialized.name);
return serializedHeaderParameter(
name,
`${name}: ${serialized.isRequired ? serialized.type : `option.Option<${serialized.type}>`}`,
`${name}: ${serialized.isRequired ? serialized.io : `optionFromNullable(${serialized.io})`}`,
serialized.isRequired,
serialized.dependencies.concat(
serialized.isRequired
? []
: [
serializedDependency('optionFromNullable', 'io-ts-types/lib/optionFromNullable'),
serializedDependency('option', 'fp-ts'),
],
),
serialized.refs,
);
};
24 changes: 19 additions & 5 deletions test/specs/2.0/json/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@
"https",
"http"
],
"parameters": {
},
"parameters": {},
"paths": {
"/pet": {
"post": {
Expand Down Expand Up @@ -70,6 +69,21 @@
"schema": {
"$ref": "./common.json#/definitions/Pet"
}
},
{
"in": "header",
"name": "Custom-Header",
"required": true,
"type": "string"
},
{
"in": "header",
"name": "Custom-Header-Two",
"required": true,
"type": "array",
"items": {
"type": "string"
}
}
],
"responses": {
Expand Down Expand Up @@ -122,9 +136,9 @@
}
}
},
"400":{
"description":"Bad Request",
"schema":{
"400": {
"description": "Bad Request",
"schema": {
"$ref": "./common.json#/definitions/ErrorResponse"
}
},
Expand Down
14 changes: 14 additions & 0 deletions test/specs/2.0/yaml/demo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ paths:
items:
type: integer
collectionFormat: multi
- in: header
name: Custom-Header
required: true
type: string
- in: header
name: Custom-Header-Two
required: false
type: string
- in: header
name: Custom-Header-Three
required: true
type: array
items:
type: string
operationId: test
responses:
200:
Expand Down
Loading

0 comments on commit 1b0c947

Please sign in to comment.