Skip to content

Commit eb7e9af

Browse files
committed
added a Java example for an API Gateway with proxy resources to HTTP backend APIs
1 parent 7f2d778 commit eb7e9af

File tree

8 files changed

+594
-0
lines changed

8 files changed

+594
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.classpath.txt
2+
target
3+
.classpath
4+
.project
5+
.idea
6+
.settings
7+
.vscode
8+
*.iml
9+
10+
# CDK asset staging directory
11+
.cdk.staging
12+
cdk.out
13+
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# HTTP Proxy APIGateway
2+
3+
<!--BEGIN STABILITY BANNER-->
4+
5+
---
6+
![Stability: Stable](https://img.shields.io/badge/stability-Stable-success.svg?style=for-the-badge)
7+
> **This is a stable example. It should successfully build out of the box**
8+
>
9+
> This example is built on Construct Libraries marked "Stable" and does not have any infrastructure prerequisites to build.
10+
---
11+
12+
<!--END STABILITY BANNER-->
13+
14+
This example creates an API Gateway with proxy resources for 2 HTTP backends.
15+
More HTTP backend APIs can be easily added.
16+
This is useful for scenarios when incoming requests must be routed to one or more backend API hosts.
17+
An HTTP proxy integration enables direct interactions between clients and backends without any intervention from API Gateway after the API method is set up.
18+
19+
> For more information on using HTTP proxy integrations with the APIGateway check out this [AWS tutorial](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-http.html).
20+
21+
> For demonstration purposes this CDK example deploys a solution that routes to the [PetsStore API](http://petstore-demo-endpoint.execute-api.com/) (from this [AWS tutorial](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-http.html)) and to the [OpenTrivia API](https://opentdb.com).
22+
> If you prefer to use your own HTTP backend APIs modify the argument used to call the [`HttpProxyApiGatewayStack`](src/main/java/com/myorg/HttpProxyApiGatewayStack.java) constructor in the [`HttpProxyApiGatewayApp`](src/main/java/com/myorg/HttpProxyApiGatewayApp.java) class.
23+
24+
## Build
25+
26+
To build this example, you need to be in this example's root directory. Then run the following:
27+
28+
```bash
29+
npm install -g aws-cdk
30+
npm install
31+
cdk synth
32+
```
33+
34+
This will install the necessary CDK, then this example's dependencies, and then build the CloudFormation template. The resulting CloudFormation template will be in the `cdk.out` directory.
35+
36+
## Deploy
37+
38+
Run `cdk deploy`.
39+
This will deploy / redeploy the Stack to AWS.
40+
After the CDK deployment is successful, 2 URL examples will be available in the terminal console output:
41+
42+
- One for the `PetStoreProxyEndPointGetRequestExample` stack output
43+
- One for the `OpenTriviaProxyEndPointGetRequestExample` stack output
44+
45+
At this point, you can copy each of the 2 URLs and paste them in the address bar of a browser to invoke the 2 APIs.
46+
47+
## Useful commands
48+
49+
* `mvn package` compile and run tests
50+
* `cdk ls` list all stacks in the app
51+
* `cdk synth` emits the synthesized CloudFormation template
52+
* `cdk deploy` deploy this stack to your default AWS account/region
53+
* `cdk diff` compare deployed stack with current state
54+
* `cdk docs` open CDK documentation
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{
2+
"app": "mvn -e -q compile exec:java",
3+
"watch": {
4+
"include": [
5+
"**"
6+
],
7+
"exclude": [
8+
"README.md",
9+
"cdk*.json",
10+
"target",
11+
"pom.xml",
12+
"src/test"
13+
]
14+
},
15+
"context": {
16+
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
17+
"@aws-cdk/core:checkSecretUsage": true,
18+
"@aws-cdk/core:target-partitions": [
19+
"aws",
20+
"aws-cn"
21+
],
22+
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
23+
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
24+
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
25+
"@aws-cdk/aws-iam:minimizePolicies": true,
26+
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
27+
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
28+
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
29+
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
30+
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
31+
"@aws-cdk/core:enablePartitionLiterals": true,
32+
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
33+
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
34+
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
35+
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
36+
"@aws-cdk/aws-route53-patters:useCertificate": true,
37+
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
38+
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
39+
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
40+
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
41+
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
42+
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
43+
"@aws-cdk/aws-redshift:columnId": true,
44+
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
45+
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
46+
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
47+
"@aws-cdk/aws-kms:aliasNameRef": true,
48+
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
49+
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
50+
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
51+
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
52+
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
53+
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
54+
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
55+
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
56+
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
57+
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
58+
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
59+
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
60+
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
61+
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
62+
"@aws-cdk/aws-eks:nodegroupNameAttribute": true,
63+
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
64+
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true,
65+
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false,
66+
"@aws-cdk/aws-s3:keepNotificationInImportedBucket": false,
67+
"@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true,
68+
"@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true,
69+
"@aws-cdk/aws-ec2:ec2SumTimeoutEnabled": true,
70+
"@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true,
71+
"@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true,
72+
"@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true,
73+
"@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true,
74+
"@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true
75+
}
76+
}

java/http-proxy-apigateway/pom.xml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
3+
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<groupId>com.myorg</groupId>
7+
<artifactId>http-proxy-apigateway</artifactId>
8+
<version>0.1</version>
9+
10+
<properties>
11+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
12+
<cdk.version>2.167.1</cdk.version>
13+
<constructs.version>[10.0.0,11.0.0)</constructs.version>
14+
<junit.version>5.7.1</junit.version>
15+
<maven.compiler.target>22</maven.compiler.target>
16+
<maven.compiler.source>22</maven.compiler.source>
17+
</properties>
18+
19+
<build>
20+
<plugins>
21+
<plugin>
22+
<groupId>org.apache.maven.plugins</groupId>
23+
<artifactId>maven-compiler-plugin</artifactId>
24+
<version>3.11.0</version>
25+
<configuration>
26+
<release>22</release>
27+
</configuration>
28+
</plugin>
29+
30+
<plugin>
31+
<groupId>org.codehaus.mojo</groupId>
32+
<artifactId>exec-maven-plugin</artifactId>
33+
<version>3.1.0</version>
34+
<configuration>
35+
<mainClass>com.myorg.HttpProxyApiGatewayApp</mainClass>
36+
</configuration>
37+
</plugin>
38+
</plugins>
39+
</build>
40+
41+
<dependencies>
42+
<!-- AWS Cloud Development Kit -->
43+
<dependency>
44+
<groupId>software.amazon.awscdk</groupId>
45+
<artifactId>aws-cdk-lib</artifactId>
46+
<version>${cdk.version}</version>
47+
</dependency>
48+
49+
<dependency>
50+
<groupId>software.constructs</groupId>
51+
<artifactId>constructs</artifactId>
52+
<version>${constructs.version}</version>
53+
</dependency>
54+
55+
<dependency>
56+
<groupId>org.junit.jupiter</groupId>
57+
<artifactId>junit-jupiter</artifactId>
58+
<version>${junit.version}</version>
59+
<scope>test</scope>
60+
</dependency>
61+
</dependencies>
62+
</project>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.myorg;
2+
3+
import software.amazon.awscdk.App;
4+
import software.amazon.awscdk.StackProps;
5+
import software.amazon.awscdk.services.apigatewayv2.HttpMethod;
6+
7+
import java.util.List;
8+
9+
import static com.myorg.HttpProxyApiGatewayStack.*;
10+
11+
public class HttpProxyApiGatewayApp {
12+
public static void main(final String[] args) {
13+
var app = new App();
14+
new HttpProxyApiGatewayStack(
15+
app,
16+
"HttpProxyApiGatewayStack",
17+
StackProps.builder()
18+
.stackName("HttpProxyApiGatewayStack")
19+
.build(),
20+
List.of(
21+
// Replace with resources corresponding to your own HTTP backend APIs if you want to.
22+
// Add more resources if you need to.
23+
new ProxyResourceParameters("PetStore", "http://petstore-demo-endpoint.execute-api.com", HttpMethod.ANY.name(), "/petstore/pets?type=fish"),
24+
new ProxyResourceParameters("OpenTrivia", "https://opentdb.com", HttpMethod.ANY.name(), "/api.php?amount=10")
25+
)
26+
);
27+
app.synth();
28+
}
29+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.myorg;
2+
3+
import software.amazon.awscdk.CfnOutput;
4+
import software.amazon.awscdk.RemovalPolicy;
5+
import software.amazon.awscdk.Stack;
6+
import software.amazon.awscdk.StackProps;
7+
import software.amazon.awscdk.services.apigateway.*;
8+
import software.constructs.Construct;
9+
10+
import java.util.List;
11+
import java.util.Map;
12+
13+
public class HttpProxyApiGatewayStack extends Stack {
14+
15+
public record ProxyResourceParameters(String resourceId, String baseUrl, String httpMethod, String exampleRequest) {
16+
17+
}
18+
19+
private final RestApi restApi;
20+
21+
public HttpProxyApiGatewayStack(final Construct scope, final String id, final StackProps props, List<ProxyResourceParameters> proxyResourceParameters) {
22+
super(scope, id, props);
23+
restApi = RestApi.Builder.create(this, "RestApi")
24+
.restApiName("RestApi")
25+
.cloudWatchRole(true)
26+
.cloudWatchRoleRemovalPolicy(RemovalPolicy.DESTROY)
27+
.endpointTypes(List.of(EndpointType.EDGE))
28+
.build();
29+
proxyResourceParameters.forEach(this::createProxyResource);
30+
}
31+
32+
private void createProxyResource(ProxyResourceParameters proxyResourceParameters) {
33+
var parentProxyResource = restApi.getRoot().addResource(proxyResourceParameters.resourceId);
34+
var proxyResource = ProxyResource.Builder.create(this, proxyResourceParameters.resourceId + "ProxyResource")
35+
.parent(parentProxyResource)
36+
.anyMethod(false)
37+
.build();
38+
var integrationOptions = IntegrationOptions.builder()
39+
.requestParameters(
40+
Map.of(
41+
"integration.request.path.proxy", "method.request.path.proxy"
42+
)
43+
)
44+
.build();
45+
var httpIntegrationProps = HttpIntegrationProps.builder()
46+
.proxy(true)
47+
.httpMethod(proxyResourceParameters.httpMethod)
48+
.options(integrationOptions)
49+
.build();
50+
var methodOptions = MethodOptions.builder()
51+
.requestParameters(
52+
Map.of(
53+
"method.request.path.proxy", true
54+
)
55+
)
56+
.build();
57+
var httpIntegration = new HttpIntegration(proxyResourceParameters.baseUrl + "/{proxy}", httpIntegrationProps);
58+
proxyResource.addMethod(proxyResourceParameters.httpMethod, httpIntegration, methodOptions);
59+
var proxyResourceUrl = restApi.urlForPath(proxyResource.getPath());
60+
CfnOutput.Builder.create(this, proxyResourceParameters.resourceId + "ProxyEndPointAnyRequestTemplate")
61+
.value(proxyResourceUrl)
62+
.build();
63+
CfnOutput.Builder.create(this, proxyResourceParameters.resourceId + "ProxyEndPointGetRequestExample")
64+
.value(proxyResourceUrl.replace("/{proxy+}", proxyResourceParameters.exampleRequest))
65+
.build();
66+
}
67+
}

0 commit comments

Comments
 (0)