Skip to content

Commit c26036f

Browse files
authored
Merge pull request #751 from mbfreder/add-graphql-sample
Added SpringBoot3-GraphQL sample
2 parents 948f76c + cc462ff commit c26036f

File tree

12 files changed

+503
-0
lines changed

12 files changed

+503
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Serverless Spring Boot 3 with GraphQL example
2+
A basic pet store written with the [Spring Boot 3 framework](https://projects.spring.io/spring-boot/). Unlike older examples, this example uses the [Spring for GraphQl](https://docs.spring.io/spring-graphql/reference/) library.
3+
4+
5+
The application can be deployed in an AWS account using the [Serverless Application Model](https://github.com/awslabs/serverless-application-model). The `template.yml` file in the root folder contains the application definition.
6+
7+
## Pre-requisites
8+
* [AWS CLI](https://aws.amazon.com/cli/)
9+
* [SAM CLI](https://github.com/awslabs/aws-sam-cli)
10+
* [Gradle](https://gradle.org/) or [Maven](https://maven.apache.org/)
11+
12+
## Deployment
13+
In a shell, navigate to the sample's folder and use the SAM CLI to build a deployable package
14+
```
15+
$ sam build
16+
```
17+
18+
This command compiles the application and prepares a deployment package in the `.aws-sam` sub-directory.
19+
20+
To deploy the application in your AWS account, you can use the SAM CLI's guided deployment process and follow the instructions on the screen
21+
22+
```
23+
$ sam deploy --guided
24+
```
25+
26+
Once the deployment is completed, the SAM CLI will print out the stack's outputs, including the new application URL. You can use `curl` to make a call to the URL
27+
28+
```
29+
...
30+
---------------------------------------------------------------------------------------------------------
31+
OutputKey-Description OutputValue
32+
---------------------------------------------------------------------------------------------------------
33+
PetStoreApi - URL for application https://xxxxxxxxxx.execute-api.us-west-2.amazonaws.com/graphQl
34+
---------------------------------------------------------------------------------------------------------
35+
36+
$ curl -X POST https://xxxxxxxxxx.execute-api.us-west-2.amazonaws.com/graphQl -d '{"query":"query petDetails {\n petById(id: \"pet-1\") {\n id\n name\n breed\n owner {\n id\n firstName\n lastName\n }\n }\n}","operationName":"petDetails"}' -H "Content-Type: application/json"
37+
38+
```
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<groupId>com.amazonaws.serverless.sample</groupId>
7+
<artifactId>serverless-springboot3-example</artifactId>
8+
<version>2.0-SNAPSHOT</version>
9+
<name>Spring Boot example for the aws-serverless-java-container library</name>
10+
<description>Simple pet store written with the Spring framework and Spring Boot</description>
11+
<url>https://aws.amazon.com/lambda/</url>
12+
13+
<parent>
14+
<groupId>org.springframework.boot</groupId>
15+
<artifactId>spring-boot-starter-parent</artifactId>
16+
<version>3.2.2</version>
17+
</parent>
18+
19+
<licenses>
20+
<license>
21+
<name>The Apache Software License, Version 2.0</name>
22+
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
23+
<distribution>repo</distribution>
24+
</license>
25+
</licenses>
26+
27+
<properties>
28+
<java.version>21</java.version>
29+
</properties>
30+
31+
<dependencies>
32+
<dependency>
33+
<groupId>org.springframework.boot</groupId>
34+
<artifactId>spring-boot-starter-graphql</artifactId>
35+
</dependency>
36+
<dependency>
37+
<groupId>org.springframework.boot</groupId>
38+
<artifactId>spring-boot-starter-web</artifactId>
39+
<exclusions>
40+
<exclusion>
41+
<groupId>org.springframework.boot</groupId>
42+
<artifactId>spring-boot-starter-tomcat</artifactId>
43+
</exclusion>
44+
</exclusions>
45+
</dependency>
46+
<dependency>
47+
<groupId>org.springframework.graphql</groupId>
48+
<artifactId>spring-graphql-test</artifactId>
49+
<scope>test</scope>
50+
</dependency>
51+
<dependency>
52+
<groupId>com.amazonaws.serverless</groupId>
53+
<artifactId>aws-serverless-java-container-springboot3</artifactId>
54+
<version>2.0.0-SNAPSHOT</version>
55+
</dependency>
56+
</dependencies>
57+
58+
<profiles>
59+
<profile>
60+
<id>shaded-jar</id>
61+
<build>
62+
<plugins>
63+
<plugin>
64+
<groupId>org.apache.maven.plugins</groupId>
65+
<artifactId>maven-shade-plugin</artifactId>
66+
<version>3.5.1</version>
67+
<configuration>
68+
<createDependencyReducedPom>false</createDependencyReducedPom>
69+
</configuration>
70+
<executions>
71+
<execution>
72+
<phase>package</phase>
73+
<goals>
74+
<goal>shade</goal>
75+
</goals>
76+
<configuration>
77+
<artifactSet>
78+
<excludes>
79+
<exclude>org.apache.tomcat.embed:*</exclude>
80+
</excludes>
81+
</artifactSet>
82+
</configuration>
83+
</execution>
84+
</executions>
85+
</plugin>
86+
</plugins>
87+
</build>
88+
</profile>
89+
<profile>
90+
<id>assembly-zip</id>
91+
<activation>
92+
<activeByDefault>true</activeByDefault>
93+
</activation>
94+
<build>
95+
<plugins>
96+
<!-- don't build a jar, we'll use the classes dir -->
97+
<plugin>
98+
<groupId>org.apache.maven.plugins</groupId>
99+
<artifactId>maven-jar-plugin</artifactId>
100+
<version>3.3.0</version>
101+
<executions>
102+
<execution>
103+
<id>default-jar</id>
104+
<phase>none</phase>
105+
</execution>
106+
</executions>
107+
</plugin>
108+
<plugin>
109+
<groupId>org.apache.maven.plugins</groupId>
110+
<artifactId>maven-install-plugin</artifactId>
111+
<version>3.1.1</version>
112+
<configuration>
113+
<skip>true</skip>
114+
</configuration>
115+
</plugin>
116+
<!-- select and copy only runtime dependencies to a temporary lib folder -->
117+
<plugin>
118+
<groupId>org.apache.maven.plugins</groupId>
119+
<artifactId>maven-dependency-plugin</artifactId>
120+
<version>3.6.1</version>
121+
<executions>
122+
<execution>
123+
<id>copy-dependencies</id>
124+
<phase>package</phase>
125+
<goals>
126+
<goal>copy-dependencies</goal>
127+
</goals>
128+
<configuration>
129+
<outputDirectory>${project.build.directory}/lib</outputDirectory>
130+
<includeScope>runtime</includeScope>
131+
</configuration>
132+
</execution>
133+
</executions>
134+
</plugin>
135+
<plugin>
136+
<groupId>org.apache.maven.plugins</groupId>
137+
<artifactId>maven-assembly-plugin</artifactId>
138+
<version>3.6.0</version>
139+
<executions>
140+
<execution>
141+
<id>zip-assembly</id>
142+
<phase>package</phase>
143+
<goals>
144+
<goal>single</goal>
145+
</goals>
146+
<configuration>
147+
<finalName>${project.artifactId}-${project.version}</finalName>
148+
<descriptors>
149+
<descriptor>src${file.separator}assembly${file.separator}bin.xml</descriptor>
150+
</descriptors>
151+
<attach>false</attach>
152+
</configuration>
153+
</execution>
154+
</executions>
155+
</plugin>
156+
</plugins>
157+
</build>
158+
</profile>
159+
</profiles>
160+
161+
162+
</project>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
4+
<id>lambda-package</id>
5+
<formats>
6+
<format>zip</format>
7+
</formats>
8+
<includeBaseDirectory>false</includeBaseDirectory>
9+
<fileSets>
10+
<!-- copy runtime dependencies with some exclusions -->
11+
<fileSet>
12+
<directory>${project.build.directory}${file.separator}lib</directory>
13+
<outputDirectory>lib</outputDirectory>
14+
<excludes>
15+
<exclude>tomcat-embed*</exclude>
16+
</excludes>
17+
</fileSet>
18+
<!-- copy all classes -->
19+
<fileSet>
20+
<directory>${project.build.directory}${file.separator}classes</directory>
21+
<includes>
22+
<include>**</include>
23+
</includes>
24+
<outputDirectory>${file.separator}</outputDirectory>
25+
</fileSet>
26+
</fileSets>
27+
</assembly>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.amazonaws.serverless.sample.springboot3;
2+
3+
import com.amazonaws.serverless.sample.springboot3.controller.PetsController;
4+
5+
import org.springframework.beans.factory.annotation.Value;
6+
import org.springframework.boot.SpringApplication;
7+
import org.springframework.boot.autoconfigure.SpringBootApplication;
8+
import org.springframework.context.annotation.Bean;
9+
import org.springframework.context.annotation.Import;
10+
import org.springframework.web.servlet.HandlerAdapter;
11+
import org.springframework.web.servlet.HandlerMapping;
12+
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
13+
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
14+
15+
16+
@SpringBootApplication
17+
@Import({ PetsController.class })
18+
public class Application {
19+
20+
// silence console logging
21+
@Value("${logging.level.root:OFF}")
22+
String message = "";
23+
24+
/*
25+
* Create required HandlerMapping, to avoid several default HandlerMapping instances being created
26+
*/
27+
@Bean
28+
public HandlerMapping handlerMapping() {
29+
return new RequestMappingHandlerMapping();
30+
}
31+
32+
/*
33+
* Create required HandlerAdapter, to avoid several default HandlerAdapter instances being created
34+
*/
35+
@Bean
36+
public HandlerAdapter handlerAdapter() {
37+
return new RequestMappingHandlerAdapter();
38+
}
39+
40+
public static void main(String[] args) {
41+
SpringApplication.run(Application.class, args);
42+
}
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.amazonaws.serverless.sample.springboot3;
2+
3+
4+
import com.amazonaws.serverless.exceptions.ContainerInitializationException;
5+
import com.amazonaws.serverless.proxy.internal.testutils.Timer;
6+
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
7+
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
8+
import com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler;
9+
import com.amazonaws.serverless.sample.springboot3.filter.CognitoIdentityFilter;
10+
import com.amazonaws.services.lambda.runtime.Context;
11+
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
12+
13+
import jakarta.servlet.DispatcherType;
14+
import jakarta.servlet.FilterRegistration;
15+
16+
import java.io.IOException;
17+
import java.io.InputStream;
18+
import java.io.OutputStream;
19+
import java.util.EnumSet;
20+
21+
22+
public class StreamLambdaHandler implements RequestStreamHandler {
23+
private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
24+
static {
25+
try {
26+
handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(Application.class);
27+
28+
// we use the onStartup method of the handler to register our custom filter
29+
handler.onStartup(servletContext -> {
30+
FilterRegistration.Dynamic registration = servletContext.addFilter("CognitoIdentityFilter", CognitoIdentityFilter.class);
31+
registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
32+
});
33+
} catch (ContainerInitializationException e) {
34+
// if we fail here. We re-throw the exception to force another cold start
35+
e.printStackTrace();
36+
throw new RuntimeException("Could not initialize Spring Boot application", e);
37+
}
38+
}
39+
40+
public StreamLambdaHandler() {
41+
// we enable the timer for debugging. This SHOULD NOT be enabled in production.
42+
Timer.enable();
43+
}
44+
45+
@Override
46+
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
47+
throws IOException {
48+
handler.proxyStream(inputStream, outputStream, context);
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.amazonaws.serverless.sample.springboot3.controller;
2+
3+
import org.springframework.graphql.data.method.annotation.Argument;
4+
import org.springframework.graphql.data.method.annotation.QueryMapping;
5+
import org.springframework.graphql.data.method.annotation.SchemaMapping;
6+
import org.springframework.stereotype.Controller;
7+
import com.amazonaws.serverless.sample.springboot3.model.Owner;
8+
import com.amazonaws.serverless.sample.springboot3.model.Pet;
9+
10+
@Controller
11+
public class PetsController {
12+
@QueryMapping
13+
public Pet petById(@Argument String id) {
14+
return Pet.getById(id);
15+
}
16+
17+
@SchemaMapping
18+
public Owner owner(Pet pet) {
19+
return Owner.getById(pet.ownerId());
20+
}
21+
}

0 commit comments

Comments
 (0)