Skip to content
This repository was archived by the owner on Feb 23, 2023. It is now read-only.

Commit 2e06174

Browse files
Merge pull request #27 from kozub/java-validation-example
Java validation example
2 parents 07639a5 + 4fc3d4f commit 2e06174

File tree

8 files changed

+368
-0
lines changed

8 files changed

+368
-0
lines changed

java/Validation/Function/pom.xml

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<groupId>demo</groupId>
5+
<artifactId>Functions</artifactId>
6+
<version>1.0</version>
7+
<packaging>jar</packaging>
8+
<name>Sample app demoing validation utility of Powertools.</name>
9+
<properties>
10+
<maven.compiler.source>11</maven.compiler.source>
11+
<maven.compiler.target>11</maven.compiler.target>
12+
<log4j.version>2.17.1</log4j.version>
13+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
14+
</properties>
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>software.amazon.lambda</groupId>
19+
<artifactId>powertools-logging</artifactId>
20+
<version>1.11.0</version>
21+
</dependency>
22+
<dependency>
23+
<groupId>software.amazon.lambda</groupId>
24+
<artifactId>powertools-validation</artifactId>
25+
<version>1.11.0</version>
26+
</dependency>
27+
<dependency>
28+
<groupId>com.amazonaws</groupId>
29+
<artifactId>aws-lambda-java-core</artifactId>
30+
<version>1.2.1</version>
31+
</dependency>
32+
33+
<!-- Test dependencies -->
34+
<dependency>
35+
<groupId>org.mockito</groupId>
36+
<artifactId>mockito-core</artifactId>
37+
<version>4.3.1</version>
38+
<scope>test</scope>
39+
</dependency>
40+
<dependency>
41+
<groupId>org.junit.jupiter</groupId>
42+
<artifactId>junit-jupiter-api</artifactId>
43+
<version>5.8.2</version>
44+
<scope>test</scope>
45+
</dependency>
46+
<dependency>
47+
<groupId>org.junit.jupiter</groupId>
48+
<artifactId>junit-jupiter-engine</artifactId>
49+
<version>5.8.2</version>
50+
<scope>test</scope>
51+
</dependency>
52+
</dependencies>
53+
54+
<build>
55+
<plugins>
56+
<plugin>
57+
<groupId>org.apache.maven.plugins</groupId>
58+
<artifactId>maven-surefire-plugin</artifactId>
59+
<!-- JUnit 5 requires Surefire version 2.22.0 or higher -->
60+
<version>2.22.0</version>
61+
</plugin>
62+
<plugin>
63+
<groupId>org.codehaus.mojo</groupId>
64+
<artifactId>aspectj-maven-plugin</artifactId>
65+
<version>1.14.0</version>
66+
<configuration>
67+
<source>${maven.compiler.source}</source>
68+
<target>${maven.compiler.target}</target>
69+
<complianceLevel>${maven.compiler.target}</complianceLevel>
70+
<aspectLibraries>
71+
<aspectLibrary>
72+
<groupId>software.amazon.lambda</groupId>
73+
<artifactId>powertools-validation</artifactId>
74+
</aspectLibrary>
75+
</aspectLibraries>
76+
</configuration>
77+
<executions>
78+
<execution>
79+
<goals>
80+
<goal>compile</goal>
81+
</goals>
82+
</execution>
83+
</executions>
84+
</plugin>
85+
</plugins>
86+
</build>
87+
</project>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package org.demo.validation;
2+
3+
import com.amazonaws.services.lambda.runtime.Context;
4+
import com.amazonaws.services.lambda.runtime.RequestHandler;
5+
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
6+
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
7+
import software.amazon.lambda.powertools.validation.Validation;
8+
9+
import java.io.BufferedReader;
10+
import java.io.IOException;
11+
import java.io.InputStreamReader;
12+
import java.net.URL;
13+
import java.util.HashMap;
14+
import java.util.Map;
15+
import java.util.stream.Collectors;
16+
17+
/**
18+
* Request handler for Lambda function which demonstrates validation of request message.
19+
*/
20+
public class InboundValidation implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
21+
22+
@Validation(inboundSchema = "classpath:/schema.json")
23+
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent, Context context) {
24+
Map<String, String> headers = new HashMap<>();
25+
26+
headers.put("Content-Type", "application/json");
27+
headers.put("X-Custom-Header", "application/json");
28+
29+
APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent()
30+
.withHeaders(headers);
31+
try {
32+
final String pageContents = this.getPageContents("https://checkip.amazonaws.com");
33+
String output = String.format("{ \"message\": \"hello world\", \"location\": \"%s\" }", pageContents);
34+
35+
return response
36+
.withStatusCode(200)
37+
.withBody(output);
38+
} catch (IOException e) {
39+
return response
40+
.withBody("{}")
41+
.withStatusCode(500);
42+
}
43+
}
44+
45+
private String getPageContents(String address) throws IOException {
46+
URL url = new URL(address);
47+
try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()))) {
48+
return br.lines().collect(Collectors.joining(System.lineSeparator()));
49+
}
50+
}
51+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema",
3+
"$id": "http://example.com/product.json",
4+
"type": "object",
5+
"title": "Product schema",
6+
"description": "JSON schema to validate Products",
7+
"default": {},
8+
"examples": [
9+
{
10+
"id": 43242,
11+
"name": "FooBar XY",
12+
"price": 258
13+
}
14+
],
15+
"required": [
16+
"id",
17+
"name",
18+
"price"
19+
],
20+
"properties": {
21+
"id": {
22+
"$id": "#/properties/id",
23+
"type": "integer",
24+
"title": "Id of the product",
25+
"description": "Unique identifier of the product",
26+
"default": 0,
27+
"examples": [
28+
43242
29+
]
30+
},
31+
"name": {
32+
"$id": "#/properties/name",
33+
"type": "string",
34+
"title": "Name of the product",
35+
"description": "Explicit name of the product",
36+
"minLength": 5,
37+
"default": "",
38+
"examples": [
39+
"FooBar XY"
40+
]
41+
},
42+
"price": {
43+
"$id": "#/properties/price",
44+
"type": "number",
45+
"title": "Price of the product",
46+
"description": "Positive price of the product",
47+
"default": 0,
48+
"exclusiveMinimum": 0,
49+
"examples": [
50+
258.99
51+
]
52+
}
53+
},
54+
"additionalProperties": true
55+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package org.demo.validation;
2+
3+
import com.amazonaws.services.lambda.runtime.Context;
4+
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
5+
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
6+
import org.junit.jupiter.api.BeforeEach;
7+
import org.junit.jupiter.api.Test;
8+
import org.mockito.Mock;
9+
import org.mockito.MockitoAnnotations;
10+
import software.amazon.lambda.powertools.validation.ValidationException;
11+
12+
import static org.junit.jupiter.api.Assertions.assertEquals;
13+
import static org.junit.jupiter.api.Assertions.assertThrows;
14+
15+
public class InboundValidationTest {
16+
17+
@Mock
18+
private Context context;
19+
private InboundValidation inboundValidation;
20+
21+
@BeforeEach
22+
void setUp() {
23+
MockitoAnnotations.openMocks(this);
24+
inboundValidation = new InboundValidation();
25+
}
26+
27+
@Test
28+
public void shouldReturnOkStatusWhenInputIsValid() {
29+
String body = "{\n" +
30+
" \"id\": 43242,\n" +
31+
" \"name\": \"FooBar XY\",\n" +
32+
" \"price\": 258\n" +
33+
" }";
34+
APIGatewayProxyRequestEvent request = new APIGatewayProxyRequestEvent().withBody(body);
35+
36+
APIGatewayProxyResponseEvent response = inboundValidation.handleRequest(request, context);
37+
38+
assertEquals(200, response.getStatusCode());
39+
}
40+
41+
@Test
42+
public void shouldThrowExceptionWhenRequestInInvalid() {
43+
String bodyWithMissedId = "{\n" +
44+
" \"name\": \"FooBar XY\",\n" +
45+
" \"price\": 258\n" +
46+
" }";
47+
APIGatewayProxyRequestEvent request = new APIGatewayProxyRequestEvent().withBody(bodyWithMissedId);
48+
49+
assertThrows(ValidationException.class, () -> inboundValidation.handleRequest(request, context));
50+
}
51+
}

java/Validation/README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Validation
2+
3+
This project contains an example of Lambda function using the validation module of Lambda Powertools for Java. For more information on this module, please refer to the [documentation](https://awslabs.github.io/aws-lambda-powertools-java/utilities/validation/).
4+
5+
## Deploy the sample application
6+
7+
This sample is based on Serverless Application Model (SAM) and you can use the SAM Command Line Interface (SAM CLI) to build it and deploy it to AWS.
8+
9+
To use the SAM CLI, you need the following tools.
10+
11+
* SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)
12+
* Java11 - [Install the Java 11](https://docs.aws.amazon.com/corretto/latest/corretto-11-ug/downloads-list.html)
13+
* Maven - [Install Maven](https://maven.apache.org/install.html)
14+
* Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community)
15+
16+
To build and deploy your application for the first time, run the following in your shell:
17+
18+
```bash
19+
sam build
20+
sam deploy --guided
21+
```

java/Validation/events/event.json

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{
2+
"body": "{\"message\": \"hello world\"}",
3+
"resource": "/{proxy+}",
4+
"path": "/path/to/resource",
5+
"httpMethod": "POST",
6+
"isBase64Encoded": false,
7+
"queryStringParameters": {
8+
"foo": "bar"
9+
},
10+
"pathParameters": {
11+
"proxy": "/path/to/resource"
12+
},
13+
"stageVariables": {
14+
"baz": "qux"
15+
},
16+
"headers": {
17+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
18+
"Accept-Encoding": "gzip, deflate, sdch",
19+
"Accept-Language": "en-US,en;q=0.8",
20+
"Cache-Control": "max-age=0",
21+
"CloudFront-Forwarded-Proto": "https",
22+
"CloudFront-Is-Desktop-Viewer": "true",
23+
"CloudFront-Is-Mobile-Viewer": "false",
24+
"CloudFront-Is-SmartTV-Viewer": "false",
25+
"CloudFront-Is-Tablet-Viewer": "false",
26+
"CloudFront-Viewer-Country": "US",
27+
"Host": "1234567890.execute-api.us-east-1.amazonaws.com",
28+
"Upgrade-Insecure-Requests": "1",
29+
"User-Agent": "Custom User Agent String",
30+
"Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)",
31+
"X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==",
32+
"X-Forwarded-For": "127.0.0.1, 127.0.0.2",
33+
"X-Forwarded-Port": "443",
34+
"X-Forwarded-Proto": "https"
35+
},
36+
"requestContext": {
37+
"accountId": "123456789012",
38+
"resourceId": "123456",
39+
"stage": "prod",
40+
"requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
41+
"requestTime": "09/Apr/2015:12:34:56 +0000",
42+
"requestTimeEpoch": 1428582896000,
43+
"identity": {
44+
"cognitoIdentityPoolId": null,
45+
"accountId": null,
46+
"cognitoIdentityId": null,
47+
"caller": null,
48+
"accessKey": null,
49+
"sourceIp": "127.0.0.1",
50+
"cognitoAuthenticationType": null,
51+
"cognitoAuthenticationProvider": null,
52+
"userArn": null,
53+
"userAgent": "Custom User Agent String",
54+
"user": null
55+
},
56+
"path": "/prod/path/to/resource",
57+
"resourcePath": "/{proxy+}",
58+
"httpMethod": "POST",
59+
"apiId": "1234567890",
60+
"protocol": "HTTP/1.1"
61+
}
62+
}
63+

java/Validation/template.yaml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Transform: AWS::Serverless-2016-10-31
3+
Description: >
4+
validation demo
5+
6+
Globals:
7+
Function:
8+
Timeout: 20
9+
Runtime: java11
10+
MemorySize: 512
11+
Tracing: Active
12+
13+
14+
Resources:
15+
ValidationFunction:
16+
Type: AWS::Serverless::Function
17+
Properties:
18+
CodeUri: Function
19+
Handler: org.demo.validation.InboundValidation::handleRequest
20+
Events:
21+
HelloWorld:
22+
Type: Api
23+
Properties:
24+
Path: /hello
25+
Method: post
26+
27+
Outputs:
28+
Api:
29+
Description: "API Gateway endpoint URL for Prod stage for Validation function"
30+
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
31+
Function:
32+
Description: "Validation Lambda Function ARN"
33+
Value: !GetAtt ValidationFunction.Arn

manifest.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@
2020
"dependencyManager": "maven",
2121
"appTemplate": "Idempotency",
2222
"javaVersion": "11"
23+
},
24+
{
25+
"directory": "java/Validation/Function",
26+
"displayName": "Demos setup of an validation Lambda function using Powertools",
27+
"dependencyManager": "maven",
28+
"appTemplate": "Validation",
29+
"javaVersion": "11"
2330
}
2431
]
2532
}

0 commit comments

Comments
 (0)