Skip to content
This repository was archived by the owner on Jul 23, 2021. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 74eb1cd

Browse files
tomsaleebatchock
authored andcommittedAug 8, 2017
Add support for multiple events for a single function (#50)
This adds support for multiple (documented) events for a single function. I've also got an extra test I created as I was learning what was going on, I can strip that out if you'd like. Great plugin BTW, thanks for your hard work. 👍
1 parent 6487928 commit 74eb1cd

File tree

2 files changed

+248
-11
lines changed

2 files changed

+248
-11
lines changed
 

‎src/documentation.js

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,8 @@ module.exports = function() {
141141

142142
getFunctionDocumentationParts: function getFunctionDocumentationParts() {
143143
const httpEvents = this._getHttpEvents();
144-
Object.keys(httpEvents).forEach(funcName => {
145-
const httpEvent = httpEvents[funcName];
144+
Object.keys(httpEvents).forEach(funcNameAndPath => {
145+
const httpEvent = httpEvents[funcNameAndPath];
146146
const path = httpEvent.path;
147147
const method = httpEvent.method.toUpperCase();
148148
this.createDocumentationParts(functionDocumentationParts, httpEvent, { path, method });
@@ -152,14 +152,13 @@ module.exports = function() {
152152
_getHttpEvents: function _getHttpEvents() {
153153
return this.serverless.service.getAllFunctions().reduce((documentationObj, functionName) => {
154154
const func = this.serverless.service.getFunction(functionName);
155-
const funcHttpEvent = func.events
156-
.filter((eventTypes) => eventTypes.http && eventTypes.http.documentation)
157-
.map((eventTypes) => eventTypes.http)[0];
158-
159-
if (funcHttpEvent) {
160-
documentationObj[functionName] = funcHttpEvent;
161-
}
162-
155+
func.events
156+
.filter((eventTypes) => eventTypes.http && eventTypes.http.documentation)
157+
.map((eventTypes) => eventTypes.http)
158+
.forEach(currEvent => {
159+
let key = functionName + currEvent.path;
160+
documentationObj[key] = currEvent;
161+
});
163162
return documentationObj;
164163
}, {});
165164
},

‎src/index.spec.js

Lines changed: 239 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,116 @@ describe('ServerlessAWSDocumentation', function () {
460460
});
461461
});
462462

463+
it('should add multiple response models with different content types for the same HTTP status code to ApiGateway methods', function () {
464+
this.serverlessMock.variables.service.custom.documentation.models = [{
465+
name: 'CreateResponseJson',
466+
contentType: "application/json",
467+
schema: {
468+
type: 'object'
469+
}
470+
}, {
471+
name: 'CreateResponseXml',
472+
contentType: "application/xml",
473+
schema: {
474+
type: 'object'
475+
}
476+
}];
477+
this.serverlessMock.service._functionNames = ['test'];
478+
this.serverlessMock.service._functions = {
479+
test: {
480+
events: [{
481+
http: {
482+
path: 'some/path',
483+
method: 'post',
484+
cors: true,
485+
private: true,
486+
documentation: {
487+
methodResponses: [
488+
{
489+
statusCode: 200,
490+
responseModels: {
491+
'application/json': 'CreateResponseJson',
492+
'application/xml': 'CreateResponseXml',
493+
},
494+
responseHeaders: [{
495+
name: 'x-header',
496+
description: 'THE header',
497+
}],
498+
},
499+
],
500+
}
501+
},
502+
}],
503+
},
504+
};
505+
506+
const resources = this.serverlessMock.service.provider.compiledCloudFormationTemplate.Resources;
507+
resources.somepath_post = {
508+
some: 'configuration',
509+
Properties: {},
510+
};
511+
512+
this.plugin.beforeDeploy();
513+
514+
expect(this.serverlessMock.service.provider.compiledCloudFormationTemplate).toEqual({
515+
Resources: {
516+
ExistingResource: {
517+
with: 'configuration',
518+
},
519+
somepath_post: {
520+
some: 'configuration',
521+
DependsOn: ['CreateResponseJsonModel', 'CreateResponseXmlModel'],
522+
Properties: {
523+
MethodResponses: [{
524+
StatusCode: '200',
525+
ResponseModels: {
526+
'application/json': 'CreateResponseJson',
527+
'application/xml': 'CreateResponseXml',
528+
},
529+
ResponseParameters: {
530+
'method.response.header.x-header': true,
531+
},
532+
}],
533+
},
534+
},
535+
CreateResponseJsonModel: {
536+
Type: 'AWS::ApiGateway::Model',
537+
Properties: {
538+
RestApiId: {
539+
Ref: 'ApiGatewayRestApi'
540+
},
541+
ContentType: 'application/json',
542+
Name: 'CreateResponseJson',
543+
Schema: {
544+
type: 'object'
545+
}
546+
}
547+
},
548+
CreateResponseXmlModel: {
549+
Type: 'AWS::ApiGateway::Model',
550+
Properties: {
551+
RestApiId: {
552+
Ref: 'ApiGatewayRestApi'
553+
},
554+
ContentType: 'application/xml',
555+
Name:'CreateResponseXml',
556+
Schema: {
557+
type: 'object'
558+
}
559+
},
560+
},
561+
},
562+
Outputs: {
563+
AwsDocApiId: {
564+
Description: 'API ID',
565+
Value: {
566+
Ref: 'ApiGatewayRestApi',
567+
},
568+
}
569+
},
570+
});
571+
});
572+
463573
it('should only add response methods with existing MethodResponses to ApiGateway methods', function () {
464574
this.serverlessMock.variables.service.custom.documentation.models = [];
465575
this.serverlessMock.service._functionNames = ['test'];
@@ -1954,6 +2064,135 @@ describe('ServerlessAWSDocumentation', function () {
19542064
});
19552065
});
19562066

2067+
it('should build documentation for all http event under a function', function (done) {
2068+
this.serverlessMock.variables.service.custom.documentation.api = {
2069+
description: 'this is an api',
2070+
};
2071+
this.serverlessMock.variables.service.custom.documentation.resources = [{
2072+
path: 'super/path',
2073+
description: 'this is a super path',
2074+
}, {
2075+
path: 'hidden/path',
2076+
description: 'this is a super secret hidden path',
2077+
}];
2078+
2079+
this.serverlessMock.service._functionNames = ['test'];
2080+
this.serverlessMock.service._functions = {
2081+
test: {
2082+
events: [{
2083+
http: {
2084+
path: 'some/path',
2085+
method: 'post',
2086+
documentation: {
2087+
summary: 'hello',
2088+
description: 'hello hello',
2089+
}
2090+
},
2091+
},{
2092+
http: {
2093+
path: 'some/other/path',
2094+
method: 'get',
2095+
documentation: {
2096+
summary: 'blah',
2097+
description: 'blah blah'
2098+
},
2099+
},
2100+
}],
2101+
},
2102+
};
2103+
2104+
this.optionsMock.stage = 'megastage';
2105+
this.optionsMock.region = 'hyperregion';
2106+
this.serverlessMock.providers.aws.naming.getStackName.and.returnValue('superstack');
2107+
this.serverlessMock.providers.aws.request.and.callFake((api, method) => {
2108+
switch (method) {
2109+
case 'describeStacks':
2110+
return Promise.resolve({
2111+
Stacks: [{
2112+
Outputs: [{
2113+
OutputKey: 'ApiKey',
2114+
OutputValue: 'nothing',
2115+
}, {
2116+
OutputKey: 'AwsDocApiId',
2117+
OutputValue: 'superid',
2118+
}],
2119+
}],
2120+
});
2121+
case 'getDocumentationParts':
2122+
return Promise.resolve({ items: [], });
2123+
case 'getDocumentationVersion':
2124+
return Promise.reject(new Error('Invalid Documentation version specified'));
2125+
default:
2126+
return Promise.resolve();
2127+
}
2128+
});
2129+
2130+
this.plugin.afterDeploy();
2131+
setTimeout(() => {
2132+
// 23
2133+
expect(this.serverlessMock.providers.aws.request).toHaveBeenCalledWith(
2134+
'APIGateway',
2135+
'getDocumentationParts',
2136+
{
2137+
restApiId: 'superid',
2138+
limit: 9999,
2139+
}
2140+
);
2141+
2142+
// Create documentation parts
2143+
expect(this.serverlessMock.providers.aws.request).toHaveBeenCalledWith(
2144+
'APIGateway',
2145+
'createDocumentationPart',
2146+
{
2147+
location: { type: 'API' },
2148+
properties: JSON.stringify({ description: 'this is an api' }),
2149+
restApiId: 'superid',
2150+
}
2151+
);
2152+
2153+
expect(this.serverlessMock.providers.aws.request).toHaveBeenCalledWith(
2154+
'APIGateway',
2155+
'createDocumentationPart',
2156+
{
2157+
location: { type: 'RESOURCE', path: 'super/path' },
2158+
properties: JSON.stringify({ description: 'this is a super path' }),
2159+
restApiId: 'superid',
2160+
}
2161+
);
2162+
2163+
expect(this.serverlessMock.providers.aws.request).toHaveBeenCalledWith(
2164+
'APIGateway',
2165+
'createDocumentationPart',
2166+
{
2167+
location: { type: 'RESOURCE', path: 'hidden/path' },
2168+
properties: JSON.stringify({ description: 'this is a super secret hidden path' }),
2169+
restApiId: 'superid',
2170+
}
2171+
);
2172+
2173+
expect(this.serverlessMock.providers.aws.request).toHaveBeenCalledWith(
2174+
'APIGateway',
2175+
'createDocumentationPart',
2176+
{
2177+
location: { path: 'some/path', method: 'POST', type: 'METHOD' },
2178+
properties: JSON.stringify({ description: 'hello hello', summary: 'hello' }),
2179+
restApiId: 'superid',
2180+
}
2181+
);
2182+
2183+
expect(this.serverlessMock.providers.aws.request).toHaveBeenCalledWith(
2184+
'APIGateway',
2185+
'createDocumentationPart',
2186+
{
2187+
location: { path: 'some/other/path', method: 'GET', type: 'METHOD' },
2188+
properties: JSON.stringify({ description: 'blah blah', summary: 'blah' }),
2189+
restApiId: 'superid',
2190+
}
2191+
);
2192+
done();
2193+
});
2194+
});
2195+
19572196
it('should not deploy when documentation version is not updated', function (done) {
19582197
spyOn(console, 'info');
19592198
this.serverlessMock.providers.aws.naming.getStackName.and.returnValue('superstack');
@@ -2434,6 +2673,5 @@ describe('ServerlessAWSDocumentation', function () {
24342673
const v4 = this.plugin.getDocumentationVersion();
24352674
expect(v4).toBe(v3);
24362675
});
2437-
24382676
});
24392677
});

0 commit comments

Comments
 (0)
This repository has been archived.