[JAVA] Écrivons une fonction Lambda qui intègre Amazon API Gateway à Spring Cloud Function.

introduction

L'implémentation des fonctions Lambda en Java peut être fastidieuse. Si vous utilisez la fonction Spring Cloud, le framework semble absorber la complexité de cette zone d'une manière agréable. Alors, j'ai essayé de voir si c'était vraiment bien absorbé et j'ai pu l'écrire rapidement.

À propos, il existe de nombreux exemples de Spring Cloud Function qui ne sont pas intégrés au proxy, mais je n'ai pas pu trouver la version intégrée, alors j'espère que cela aidera à la considérer.

Constitution

Créez un projet Maven comme celui ci-dessous.

SpringCloudFunctionTest
├── pom.xml
├── serverless.yml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── springcloudfunctiontest
    │   │           ├── AWSLambdaHandler.java
    │   │           ├── Hello.java
    │   │           └── SpringCloudFunctionExampleApplication.java
    │   └── resources
    │       └── application.properties
    └── test
        └── java
            └── com
                └── springcloudfunctiontest
                    └── SpringCloudFunctionExampleApplicationTests.java

pom.xml devrait ressembler à ceci.

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.techprimers.serverless</groupId>
    <artifactId>spring-cloud-function-test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-cloud-function-test</name>
    <description>Demo project for Spring Boot with Spring Cloud Function</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-function-adapter-aws</artifactId>
        </dependency>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-lambda-java-events</artifactId>
            <version>2.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-lambda-java-core</artifactId>
            <version>1.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR2</version>
                <type>pom</type>
                <scope>import</scope>
                </dependency>
            </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <dependencies>
                    <dependency>
                        <groupId>org.springframework.boot.experimental</groupId>
                        <artifactId>spring-boot-thin-layout</artifactId>
                        <version>1.0.10.RELEASE</version>
                    </dependency>
                </dependencies>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <configuration>
                    <createDependencyReducedPom>false</createDependencyReducedPom>
                    <shadedArtifactAttached>true</shadedArtifactAttached>
                    <shadedClassifierName>aws</shadedClassifierName>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Code du gestionnaire

Créez une classe qui fait `` SpringApplication.run '' comme une application Spring Boot normale.

SpringCloudFunctionExampleApplication.java


package com.springcloudfunctiontest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringCloudFunctionExampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudFunctionExampleApplication.class, args);
    }

}

Alors, créez un gestionnaire d'événements pour Lambda. Pour être honnête, je ne sais pas pourquoi cette classe est vide ... Puisqu'il est placé sur le back-end d'API Gateway, définissez respectivement APIGatewayProxyRequestEvent`` et APIGatewayProxyResponseEvent``` pour l'entrée et la sortie.

AWSLambdaHandler.java


package com.springcloudfunctiontest;

import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import org.springframework.cloud.function.adapter.aws.SpringBootRequestHandler;

public class AWSLambdaHandler extends SpringBootRequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
}

Enfin, créez une classe de logique métier. ``APIGatewayProxyRequestEventQuandAPIGatewayProxyResponseEvent```Les spécifications sontjavadocAllons vérifier.

Cependant, même si Spring Cloud Function est compatible avec plusieurs clouds, si vous utilisez une telle interface, il s'agira d'une implémentation entièrement spécifique à AWS.

Ne vous inquiétez pas de la gestion désordonnée de JSON dans le dernier setBody.

Hello.java


package com.springcloudfunctiontest;

import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import org.springframework.stereotype.Component;

import java.util.function.Function;
import java.util.Map;

@Component
public class Hello implements Function<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
    @Override
    public APIGatewayProxyResponseEvent apply(APIGatewayProxyRequestEvent input) {
        Map<String, String> queryStringParameter = input.getQueryStringParameters();

        String id = queryStringParameter.get("id");
        String name = null;

        if( id.equals("11111") ) {
          name = "\"Taro\"";
        } else {
          name = "\"Nanashi\"";
        }

        APIGatewayProxyResponseEvent responseEvent = new APIGatewayProxyResponseEvent();
        responseEvent.setStatusCode(200);
        responseEvent.setBody("{\"name\":" + name + "}");
        return responseEvent;
    }
}

#Code de test Vous pouvez écrire le code de test normalement.

SpringCloudFunctionExampleApplicationTests.java


package com.springcloudfunctiontest;

import java.util.HashMap;
import java.util.Map;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import static org.assertj.core.api.Assertions.assertThat;

import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringCloudFunctionExampleApplicationTests {

    @Test
    public void HelloTest1() {
        Hello hello = new Hello();
        APIGatewayProxyRequestEvent request = new APIGatewayProxyRequestEvent();

        Map<String,String> queryStringParameter = new HashMap<>();
        queryStringParameter.put("id", "11111");
        request.setQueryStringParameters(queryStringParameter);

        APIGatewayProxyResponseEvent response = hello.apply(request);

        assertThat(response.getBody()).isEqualTo("{\"name\":\"Taro\"}");
    }

    @Test
    public void HelloTest2() {
        Hello hello = new Hello();
        APIGatewayProxyRequestEvent request = new APIGatewayProxyRequestEvent();

        Map<String,String> queryStringParameter = new HashMap<>();
        queryStringParameter.put("id", "22222");
        request.setQueryStringParameters(queryStringParameter);

        APIGatewayProxyResponseEvent response = hello.apply(request);

        assertThat(response.getBody()).isEqualTo("{\"name\":\"Nanashi\"}");
    }
}

#Déployer Il est difficile de télécharger manuellement sur S3 ou d'attendre la construction du pipeline, alors déployons-le sur Texto avec Serverless Framework car ce n'est pas une version officielle de l'application.

serverless.yml


service: test

provider:
  name: aws
  runtime: java8
  timeout: 30

  region: ap-northeast-1

package:
  artifact: target/spring-cloud-function-test-0.0.1-SNAPSHOT-aws.jar

functions:
  hello:
    handler: org.springframework.cloud.function.adapter.aws.SpringBootStreamHandler
    events:
      - http:
          path: testapi
          method: get
          integration: lambda-proxy
          request:
            template:
              application/json: '$input.json("$")'

Lorsque vous déployez avec cela, l'API REST sera renvoyée correctement comme ceci!

$ curl -X GET https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/testapi?id=11111; echo
{"name":"Taro"}

#Conclusion Eh bien, je n'ai pas du tout profité du framework Spring, donc j'ai l'impression que c'est le même effort que lorsque j'ai créé un gestionnaire d'événements Lambda normal. Serait-il apprécié que nous puissions utiliser davantage les fonctionnalités du framework?

Cette fois, je comprends que si vous écrivez des fonctions Lambda en Java, il est plus facile de les implémenter à l'aide d'APIGatewayProxyRequestEvent, et il est plus facile de déployer Serverless Framework.

Recommended Posts

Écrivons une fonction Lambda qui intègre Amazon API Gateway à Spring Cloud Function.
[Débutant] Essayez d'écrire l'API REST pour l'application Todo avec Spring Boot
Configurer des microservices avec Spring Cloud (4): API Gateway
Implémentons une fonction pour limiter le nombre d'accès à l'API avec SpringBoot + Redis
Faisons une API simple avec EC2 + RDS + Spring boot ①
Créer un SlackBot avec AWS lambda et API Gateway en Java
Authentification Oauth2 avec Spring Cloud Gateway
Écrivons un code de test pour la fonction de connexion avec Spring Boot
Expliquons en détail Spring Cloud Gateway
Envoyez une demande au backend après une authentification unique avec Spring Cloud Gateway
Faisons une fonction de recherche avec Rails (ransack)
Créer un serveur API Web avec Spring Boot
J'ai créé une fonction pour enregistrer des images avec l'API dans Spring Framework. Partie 1 (édition API)
[Compatible JUnit 5] Ecrire un test en utilisant JUnit 5 avec Spring boot 2.2, 2.3
Implémentez une API Rest simple avec Spring Security avec Spring Boot 2.0
[JUnit 5] Ecrivez un test de validation avec Spring Boot! [Test de paramétrage]
J'ai créé une fonction pour enregistrer des images avec l'API dans Spring Framework. Partie 2 (édition client)
Découvrons comment recevoir avec Request Body avec l'API REST de Spring Boot