Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for defining/importing api gateway models #2102

Closed
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Convert MethodResponse to a class, to enable an API allowing content …
…type to be inferred from a created model.

Fix methodresponse usage in README, and update formatting of integration test expected files.

Convert JsonSchemaSchema enum to a static class, to fix build errors.

Fix README for changes in JsonSchemaSchema, again.
john-shaskin committed Apr 2, 2019
commit 3161b426011fd6540dc968bb1d80f335a6a3561a
19 changes: 10 additions & 9 deletions packages/@aws-cdk/aws-apigateway/README.md
Original file line number Diff line number Diff line change
@@ -157,7 +157,7 @@ REST API as follows:
const beerModel = api.addModel('Beer', {
contentType: 'application/json',
schema: {
$schema: 'http://json-schema.org/draft-04/schema#',
$schema: JsonSchemaSchema.draft4,
title: 'Beer',
type: 'object',
properties: {
@@ -177,7 +177,7 @@ const breweryModel = new apiGateway.Model(this, 'breweryModel', {
description: 'Simple model for defining a brewery.',
contentType: 'application/json',
schema: {
$schema: 'http://json-schema.org/draft-04/schema#',
$schema: JsonSchemaSchema.draft4,
title: 'Brewery',
type: 'object',
properties: {
@@ -200,13 +200,14 @@ RequestModel support not yet implemented.

```ts
const method = api.beer.addMethod('GET', getBeerLambdaHandler, {
methodResponses: [{
statusCode: '200',
responseModels: {
'application/json': beerModelJson,
'application/xml': beerModelXml,
}
}]
methodResponses: [
new MethodResponse({ statusCode: '200' })
.addResponseModel(beerModelJson)
.addResonseModel(beerModelXml),
new MethodResponse({ statusCode: '400' })
.addResponseModel(errorModelJson)
.addResonseModel(errorModelXml),
]
});
```

14 changes: 14 additions & 0 deletions packages/@aws-cdk/aws-apigateway/lib/json-schema.ts
Original file line number Diff line number Diff line change
@@ -69,4 +69,18 @@ export class JsonSchemaMapper {
}

private static readonly PropsWithPrefix = ['schema', 'ref'];
}

export class JsonSchemaSchema {
public static get draft4(): string {
return JsonSchemaSchema.schemaUrlTemplate('draft-04');
}

public static get draft7(): string {
return JsonSchemaSchema.schemaUrlTemplate('draft-07');
}

public static schemaUrlTemplate(draft: string): string {
return `http://json-schema.org/${draft}/schema#`;
}
}
6 changes: 3 additions & 3 deletions packages/@aws-cdk/aws-apigateway/lib/method.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ import cdk = require('@aws-cdk/cdk');
import { CfnMethod, CfnMethodProps } from './apigateway.generated';
import { ConnectionType, Integration } from './integration';
import { MockIntegration } from './integrations/mock';
import { MethodResponse } from './methodresponse';
import { IMethodResponse } from './methodresponse';
import { IRestApiResource } from './resource';
import { RestApi } from './restapi';
import { validateHttpMethod } from './util';
@@ -44,7 +44,7 @@ export interface MethodOptions {
* for the integration response to be correctly mapped to a response to the client.
* @see https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-method-settings-method-response.html
*/
readonly methodResponses?: MethodResponse[]
readonly methodResponses?: IMethodResponse[]

/**
* The request parameters that API Gateway accepts. Specify request parameters
@@ -209,7 +209,7 @@ export class Method extends cdk.Construct {
};
}

private renderMethodResponses(methodResponses: MethodResponse[] | undefined): CfnMethod.MethodResponseProperty[] | undefined {
private renderMethodResponses(methodResponses: IMethodResponse[] | undefined): CfnMethod.MethodResponseProperty[] | undefined {
if (!methodResponses) {
// Fall back to nothing
return undefined;
43 changes: 41 additions & 2 deletions packages/@aws-cdk/aws-apigateway/lib/methodresponse.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IModelRef } from './model';
import { IModelRef, Model } from './model';

export interface MethodResponse {
export interface IMethodResponse {

/**
* The method response's status code, which you map to an IntegrationResponse.
@@ -25,4 +25,43 @@ export interface MethodResponse {
* @default None
*/
readonly responseModels?: { [contentType: string]: IModelRef };
}

export interface MethodResponseProps {
readonly statusCode: string;
readonly responseParameters?: { [destination: string]: boolean };
readonly responseModels?: { [contentType: string]: IModelRef };
}

export class MethodResponse implements IMethodResponse {
public readonly statusCode: string;
public readonly responseParameters?: { [destination: string]: boolean };
private responseModelsInt?: { [contentType: string]: IModelRef };

public get responseModels(): { [contentType: string]: IModelRef } | undefined {
return this.responseModelsInt;
}

constructor(props: MethodResponseProps) {
this.statusCode = props.statusCode;
this.responseParameters = props.responseParameters;
this.responseModelsInt = props.responseModels;
}

public addResponseModelForContentType(contentType: string, model: IModelRef) {
if (!this.responseModelsInt) {
this.responseModelsInt = {};
}

if (this.responseModelsInt[contentType]) {
throw new Error(`A model has already been registered for the content type ${contentType}`);
}
this.responseModelsInt[contentType] = model;

return this;
}

public addResponseModel(model: Model): MethodResponse {
return this.addResponseModelForContentType(model.contentType, model);
}
}
6 changes: 6 additions & 0 deletions packages/@aws-cdk/aws-apigateway/lib/model.ts
Original file line number Diff line number Diff line change
@@ -144,6 +144,11 @@ export class Model extends cdk.Construct implements IModel {
*/
public readonly restApi: IRestApi;

/**
* The content type for the model.
*/
public readonly contentType: string;

constructor(scope: cdk.Construct, id: string, props: ModelProps) {
super(scope, id);

@@ -157,6 +162,7 @@ export class Model extends cdk.Construct implements IModel {

this.modelId = model.ref;
this.restApi = props.restApi;
this.contentType = props.contentType;
}

/**
Original file line number Diff line number Diff line change
@@ -148,8 +148,7 @@
"Effect": "Allow",
"Principal": {
"Service": {
"Fn::Join":
[
"Fn::Join": [
"",
[
"lambda.",
@@ -287,7 +286,7 @@
"Type": "AWS::ApiGateway::Deployment",
"Properties": {
"RestApiId": {
"Ref": "beerapi67AE41CF"
"Ref": "beerapi67AE41CF"
},
"Description": "Automatically created by the RestApi construct"
},
@@ -302,17 +301,17 @@
"Type": "AWS::ApiGateway::Stage",
"Properties": {
"RestApiId": {
"Ref": "beerapi67AE41CF"
"Ref": "beerapi67AE41CF"
},
"DeploymentId": {
"Ref": "beerapiDeployment3077C14B2cae185d40ed71262560f2f6141fd859"
"Ref": "beerapiDeployment3077C14B2cae185d40ed71262560f2f6141fd859"
},
"StageName": "prod"
}
},
"beerapiCloudWatchRole81F996BB": {
"Type": "AWS::IAM::Role",
"Properties": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
@@ -366,8 +365,8 @@
]
},
"beerapibeerCF23738E": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"ParentId": {
"Fn::GetAtt": [
"beerapi67AE41CF",
@@ -376,7 +375,7 @@
},
"PathPart": "beer",
"RestApiId": {
"Ref": "beerapi67AE41CF"
"Ref": "beerapi67AE41CF"
}
}
},
@@ -407,7 +406,7 @@
"Ref": "AWS::Region"
},
":lambda:path/2015-03-31/functions/",
{
{
"Fn::GetAtt": [
"BeersHandlerA9F3A7B5",
"Arn"
@@ -421,9 +420,9 @@
"MethodResponses": [
{
"ResponseModels": {
"application/json": {
"Ref": "beerapiBeerSummaryModel1EE635AB"
}
"application/json": {
"Ref": "beerapiBeerSummaryModel1EE635AB"
}
},
"StatusCode": "200"
}
@@ -446,10 +445,10 @@
"Type": "AWS::ApiGateway::Method",
"Properties": {
"HttpMethod": "GET",
"ResourceId":{
"ResourceId": {
"Ref": "beerapibeerbeerid64F377BE"
},
"RestApiId":{
"RestApiId": {
"Ref": "beerapi67AE41CF"
},
"AuthorizationType": "NONE",
@@ -482,10 +481,10 @@
},
"MethodResponses": [
{
"ResponseModels":{
"application/json": {
"Ref": "beerapiBeerDetailsModel5D942EB5"
}
"ResponseModels": {
"application/json": {
"Ref": "beerapiBeerDetailsModel5D942EB5"
}
},
"StatusCode": "200"
}
@@ -495,8 +494,8 @@
"beerapiBeerSummaryModel1EE635AB": {
"Type": "AWS::ApiGateway::Model",
"Properties": {
"RestApiId":{
"Ref": "beerapi67AE41CF"
"RestApiId": {
"Ref": "beerapi67AE41CF"
},
"ContentType": "application/json",
"Description": "A basic summary for a beer. Used for listing a bunch of beers at a glance.",
@@ -506,8 +505,12 @@
"title": "BeerSummary",
"type": "object",
"properties": {
"id": { "type": "string" },
"name": { "type": "string" }
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
}
@@ -526,9 +529,15 @@
"title": "Brewery",
"type": "object",
"properties": {
"id": { "type": "string" },
"name": { "type": "string" },
"address": { "type": "string" },
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"address": {
"type": "string"
},
"beers": {
"type": "array",
"items": {
@@ -571,33 +580,43 @@
"title": "Beer",
"type": "object",
"properties": {
"id": { "type": "string" },
"name": { "type": "string" },
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"brewery": {
"type": "object",
"$ref": {
"Fn::Join": [
"",
[
"https://apigateway.",
{
"Ref": "AWS::URLSuffix"
},
"/restapis/",
{
"Ref": "beerapi67AE41CF"
},
"/models/",
{
"Ref": "beerapiBreweryModelA8E987E0"
}
]
"Fn::Join": [
"",
[
"https://apigateway.",
{
"Ref": "AWS::URLSuffix"
},
"/restapis/",
{
"Ref": "beerapi67AE41CF"
},
"/models/",
{
"Ref": "beerapiBreweryModelA8E987E0"
}
]
}
]
}
},
"style": {
"type": "string"
},
"style": { "type": "string" },
"abv": { "type": "number" },
"ibu": { "type": "number"}
"abv": {
"type": "number"
},
"ibu": {
"type": "number"
}
}
}
}
Loading