redoc/src/services/models/Operation.ts

168 lines
4.2 KiB
TypeScript
Raw Normal View History

2018-01-22 21:30:53 +03:00
import { action, observable } from 'mobx';
2017-10-12 00:01:37 +03:00
import { IMenuItem } from '../MenuStore';
import { GroupModel } from './Group.model';
2018-01-22 21:30:53 +03:00
import { SecurityRequirementModel } from './SecurityRequirement';
2017-10-12 00:01:37 +03:00
import { OpenAPIExternalDocumentation, OpenAPIServer, OpenAPIXCodeSample } from '../../types';
2017-10-12 00:01:37 +03:00
import {
getOperationSummary,
getStatusCodeType,
isStatusCode,
JsonPointer,
2018-07-26 17:34:44 +03:00
memoize,
mergeParams,
normalizeServers,
sortByRequired,
} from '../../utils';
2018-01-22 21:30:53 +03:00
import { ContentItemModel, ExtendedOpenAPIOperation } from '../MenuBuilder';
import { OpenAPIParser } from '../OpenAPIParser';
import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
2017-10-12 00:01:37 +03:00
import { FieldModel } from './Field';
import { RequestBodyModel } from './RequestBody';
2018-01-22 21:30:53 +03:00
import { ResponseModel } from './Response';
2017-10-12 00:01:37 +03:00
/**
* Operation model ready to be used by components
*/
export class OperationModel implements IMenuItem {
//#region IMenuItem fields
id: string;
absoluteIdx?: number;
name: string;
description?: string;
type = 'operation' as 'operation';
parent?: GroupModel;
externalDocs?: OpenAPIExternalDocumentation;
2018-01-22 21:30:53 +03:00
items: ContentItemModel[] = [];
2017-10-12 00:01:37 +03:00
depth: number;
@observable ready?: boolean = true;
@observable active: boolean = false;
@observable expanded: boolean = false;
2017-10-12 00:01:37 +03:00
//#endregion
2018-07-26 17:34:44 +03:00
pointer: string;
2017-10-12 00:01:37 +03:00
operationId?: string;
httpVerb: string;
deprecated: boolean;
path: string;
servers: OpenAPIServer[];
security: SecurityRequirementModel[];
codeSamples: OpenAPIXCodeSample[];
2017-10-12 00:01:37 +03:00
2017-11-21 14:00:33 +03:00
constructor(
2018-07-26 17:34:44 +03:00
private parser: OpenAPIParser,
private operationSpec: ExtendedOpenAPIOperation,
2017-11-21 14:00:33 +03:00
parent: GroupModel | undefined,
2018-07-26 17:34:44 +03:00
private options: RedocNormalizedOptions,
2017-11-21 14:00:33 +03:00
) {
2018-07-26 17:34:44 +03:00
this.pointer = JsonPointer.compile(['paths', operationSpec.pathName, operationSpec.httpVerb]);
this.id =
operationSpec.operationId !== undefined
? 'operation/' + operationSpec.operationId
: parent !== undefined
2018-07-26 17:34:44 +03:00
? parent.id + this.pointer
: this.pointer;
2017-10-12 00:01:37 +03:00
this.name = getOperationSummary(operationSpec);
this.description = operationSpec.description;
this.parent = parent;
this.externalDocs = operationSpec.externalDocs;
this.deprecated = !!operationSpec.deprecated;
this.httpVerb = operationSpec.httpVerb;
this.deprecated = !!operationSpec.deprecated;
this.operationId = operationSpec.operationId;
this.codeSamples = operationSpec['x-code-samples'] || [];
2018-07-26 17:34:44 +03:00
this.path = operationSpec.pathName;
2017-10-12 00:01:37 +03:00
this.servers = normalizeServers(
parser.specUrl,
operationSpec.servers || parser.spec.servers || [],
2017-10-12 00:01:37 +03:00
);
this.security = (operationSpec.security || parser.spec.security || []).map(
security => new SecurityRequirementModel(security, parser),
);
2017-10-12 00:01:37 +03:00
}
/**
* set operation as active (used by side menu)
*/
@action
activate() {
this.active = true;
}
/**
* set operation as inactive (used by side menu)
*/
@action
deactivate() {
this.active = false;
}
2018-07-26 17:34:44 +03:00
expand() {
if (this.parent) {
this.parent.expand();
}
}
collapse() {
/* do nothing */
}
2018-07-26 17:34:44 +03:00
@memoize
get requestBody() {
return (
this.operationSpec.requestBody &&
new RequestBodyModel(this.parser, this.operationSpec.requestBody, this.options)
);
}
@memoize
get parameters() {
const _parameters = mergeParams(
this.parser,
this.operationSpec.pathParameters,
this.operationSpec.parameters,
// TODO: fix pointer
).map(paramOrRef => new FieldModel(this.parser, paramOrRef, this.pointer, this.options));
if (this.options.requiredPropsFirst) {
sortByRequired(_parameters);
}
return _parameters;
}
@memoize
get responses() {
let hasSuccessResponses = false;
return Object.keys(this.operationSpec.responses || [])
.filter(code => {
if (code === 'default') {
return true;
}
if (getStatusCodeType(code) === 'success') {
hasSuccessResponses = true;
}
return isStatusCode(code);
}) // filter out other props (e.g. x-props)
.map(code => {
return new ResponseModel(
this.parser,
code,
hasSuccessResponses,
this.operationSpec.responses[code],
this.options,
);
});
}
2017-10-12 00:01:37 +03:00
}