diff --git a/aws-lambda-project/.localstack/01_init.sh b/aws-lambda-project/.localstack/01_init.sh old mode 100644 new mode 100755 index 828fd019..b82addad --- a/aws-lambda-project/.localstack/01_init.sh +++ b/aws-lambda-project/.localstack/01_init.sh @@ -1,11 +1,66 @@ #!/usr/bin/env bash -awslocal s3 mb s3://testbucket -echo "List of S3 buckets:" -echo "-------------------------------" -awslocal s3 ls - -awslocal sqs create-queue --queue-name test_queue -echo "List of SQS Queues:" -echo "-------------------------------" -awslocal sqs list-queues +# Navigate to the directory containing the JAR file +cd /localstackTemp || exit 1 + +# Set variables +JAR_FILE="aws-lambda-project-0.0.1-SNAPSHOT-aws.jar" +FUNCTION_NAME="localstack-lambda-url-example" +IAM_ROLE_ARN="arn:aws:iam::000000000000:role/lambda-role" + +# Function to display an error message and exit +error_exit() { + echo "Error: $1" >&2 + exit 1 +} + +# Check if the JAR file exists +if [ ! -f "$JAR_FILE" ]; then + error_exit "JAR file not found at $JAR_FILE" +fi + +# Set environment variables (modify as needed) +ENV_VARS='{"Variables": {"SPRING_DATASOURCE_URL":"jdbc:postgresql://postgresqldb:5432/appdb", "SPRING_DATASOURCE_USERNAME":"appuser", "SPRING_DATASOURCE_PASSWORD":"secret"}}' + +# Create Lambda function +awslocal lambda create-function \ + --function-name "$FUNCTION_NAME" \ + --runtime java17 \ + --timeout 10 \ + --handler org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest \ + --role "$IAM_ROLE_ARN" \ + --zip-file "fileb://$JAR_FILE" \ + --environment "$ENV_VARS" + +echo -e "Lambda function created successfully!\n" + +# Create function URL configuration and capture the output +function_url_response=$(awslocal lambda create-function-url-config --function-name "$FUNCTION_NAME" --auth-type NONE) + +# Use jq to extract the FunctionUrl +function_url=$(echo "$function_url_response" | grep -o '"FunctionUrl": "[^"]*' | cut -d'"' -f4) + +# Print the extracted FunctionUrl +echo "FunctionUrl: $function_url" +echo -e "Function URL configuration created!\n" + +# Wait until the function is active +awslocal lambda wait function-active-v2 --function-name "$FUNCTION_NAME" +echo -e "Lambda function is now active\n" + +# Invoke Lambda function or use curl +#awslocal lambda invoke \ +# --function-name "$FUNCTION_NAME" \ +# --payload '{"body": "{\"name\": \"profile\"}" }' \ +# output.txt +# +#echo -e "Lambda function invoked successfully\n" + +# Use curl to invoke Lambda function and capture the response +response_from_curl=$(curl -X POST \ + "$function_url" \ + -H 'Content-Type: application/json' \ + -d '{"name": "profile"}') + +# Print the response from curl +echo "Response from curl: $response_from_curl" diff --git a/aws-lambda-project/README.md b/aws-lambda-project/README.md index d528099d..68ce4ba1 100644 --- a/aws-lambda-project/README.md +++ b/aws-lambda-project/README.md @@ -1,5 +1,7 @@ # aws-lambda-project +Request must be smaller than 69905067 bytes for the CreateFunction operation in aws lambda + ### Format code ```shell diff --git a/aws-lambda-project/docker/docker-compose.yml b/aws-lambda-project/docker/docker-compose.yml index 774e5a26..065a71af 100644 --- a/aws-lambda-project/docker/docker-compose.yml +++ b/aws-lambda-project/docker/docker-compose.yml @@ -2,25 +2,33 @@ version: '3.8' services: postgresqldb: - image: postgres:16.0-alpine + image: postgres:16.1-alpine environment: - POSTGRES_USER=appuser - POSTGRES_PASSWORD=secret - POSTGRES_DB=appdb ports: - "5432:5432" + networks: + - aws-lambda localstack: - image: localstack/localstack:2.3.2 + image: localstack/localstack:3.0.0 ports: - - "4566:4566" + - "127.0.0.1:4566:4566" # LocalStack Gateway + - "127.0.0.1:4510-4559:4510-4559" # external services port range environment: - - SERVICES=s3,sqs - - DEFAULT_REGION=us-east-1 + - DEBUG=${DEBUG-} - DOCKER_HOST=unix:///var/run/docker.sock - - USE_SSL=0 - - AWS_CBOR_DISABLE=1 + - SERVICES=lambda + - LAMBDA_RUNTIME_ENVIRONMENT_TIMEOUT=30 volumes: + - "../target:/localstackTemp" - "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack" - "/var/run/docker.sock:/var/run/docker.sock" - "../.localstack:/etc/localstack/init/ready.d" # ready hook + networks: + - aws-lambda + +networks: + aws-lambda: \ No newline at end of file diff --git a/aws-lambda-project/pom.xml b/aws-lambda-project/pom.xml index 8afea218..9617bd7b 100644 --- a/aws-lambda-project/pom.xml +++ b/aws-lambda-project/pom.xml @@ -24,7 +24,8 @@ 2022.0.4 3.0.3 2.2.0 - 2.15.0 + 1.0.31.RELEASE + 2.21.28 ${project.build.directory}/test-results 2.40.0 @@ -46,38 +47,19 @@ org.springframework.boot spring-boot-starter-actuator - - org.springframework.boot - spring-boot-starter-validation - org.springframework.boot spring-boot-starter-web - org.springframework.boot - spring-boot-devtools - runtime - true + org.springframework.cloud + spring-cloud-function-adapter-aws - org.springframework.boot - spring-boot-configuration-processor - true - - - org.projectlombok - lombok - true - - - io.awspring.cloud - spring-cloud-aws-starter - - - io.awspring.cloud - spring-cloud-aws-starter-sqs + software.amazon.awssdk + lambda + org.springframework.boot spring-boot-starter-data-jpa @@ -91,20 +73,6 @@ org.liquibase liquibase-core - - org.springdoc - springdoc-openapi-starter-webmvc-ui - ${springdoc-openapi.version} - - - org.apache.commons - commons-lang3 - - - commons-io - commons-io - ${commons-io.version} - org.springframework.boot @@ -116,11 +84,6 @@ spring-boot-testcontainers test - - org.awaitility - awaitility - test - org.testcontainers junit-jupiter @@ -136,6 +99,17 @@ localstack test + + org.apache.maven.shared + maven-invoker + 3.2.0 + test + + + io.rest-assured + rest-assured + test + @@ -154,14 +128,35 @@ pom import + + software.amazon.awssdk + bom + ${aws.java.sdk.version} + pom + import + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + org.springframework.boot spring-boot-maven-plugin + + + org.springframework.boot.experimental + spring-boot-thin-layout + ${wrapper.version} + + @@ -170,6 +165,16 @@ + + org.apache.maven.plugins + maven-shade-plugin + 3.5.1 + + false + true + aws + + io.github.git-commit-id git-commit-id-maven-plugin diff --git a/aws-lambda-project/src/main/java/com/learning/awslambda/Application.java b/aws-lambda-project/src/main/java/com/learning/awslambda/Application.java index bf5e8024..4c051cb1 100644 --- a/aws-lambda-project/src/main/java/com/learning/awslambda/Application.java +++ b/aws-lambda-project/src/main/java/com/learning/awslambda/Application.java @@ -1,12 +1,9 @@ package com.learning.awslambda; -import com.learning.awslambda.config.ApplicationProperties; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; @SpringBootApplication -@EnableConfigurationProperties({ApplicationProperties.class}) public class Application { public static void main(String[] args) { diff --git a/aws-lambda-project/src/main/java/com/learning/awslambda/config/AWSLambdaConfig.java b/aws-lambda-project/src/main/java/com/learning/awslambda/config/AWSLambdaConfig.java new file mode 100644 index 00000000..42bedaf7 --- /dev/null +++ b/aws-lambda-project/src/main/java/com/learning/awslambda/config/AWSLambdaConfig.java @@ -0,0 +1,17 @@ +package com.learning.awslambda.config; + +import com.learning.awslambda.model.request.ActorRequest; +import com.learning.awslambda.model.response.ActorResponse; +import com.learning.awslambda.services.ActorService; +import java.util.function.Function; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +public class AWSLambdaConfig { + + @Bean + Function findActorByName(ActorService actorService) { + return request -> actorService.findActorByName(request.name()); + } +} diff --git a/aws-lambda-project/src/main/java/com/learning/awslambda/config/ApplicationProperties.java b/aws-lambda-project/src/main/java/com/learning/awslambda/config/ApplicationProperties.java deleted file mode 100644 index 7b3ff461..00000000 --- a/aws-lambda-project/src/main/java/com/learning/awslambda/config/ApplicationProperties.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.learning.awslambda.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.NestedConfigurationProperty; - -@Data -@ConfigurationProperties("application") -public class ApplicationProperties { - - @NestedConfigurationProperty - private Cors cors = new Cors(); - - @Data - public static class Cors { - private String pathPattern = "/api/**"; - private String allowedMethods = "*"; - private String allowedHeaders = "*"; - private String allowedOriginPatterns = "*"; - private boolean allowCredentials = true; - } -} diff --git a/aws-lambda-project/src/main/java/com/learning/awslambda/config/Initializer.java b/aws-lambda-project/src/main/java/com/learning/awslambda/config/Initializer.java deleted file mode 100644 index 812d5120..00000000 --- a/aws-lambda-project/src/main/java/com/learning/awslambda/config/Initializer.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.learning.awslambda.config; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.CommandLineRunner; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -@Slf4j -public class Initializer implements CommandLineRunner { - - private final ApplicationProperties properties; - - @Override - public void run(String... args) { - log.info("Running Initializer....."); - } -} diff --git a/aws-lambda-project/src/main/java/com/learning/awslambda/config/SwaggerConfig.java b/aws-lambda-project/src/main/java/com/learning/awslambda/config/SwaggerConfig.java deleted file mode 100644 index 611e5c85..00000000 --- a/aws-lambda-project/src/main/java/com/learning/awslambda/config/SwaggerConfig.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.learning.awslambda.config; - -import io.swagger.v3.oas.annotations.OpenAPIDefinition; -import io.swagger.v3.oas.annotations.info.Info; -import io.swagger.v3.oas.annotations.servers.Server; -import org.springframework.context.annotation.Configuration; - -@Configuration(proxyBeanMethods = false) -@OpenAPIDefinition(info = @Info(title = "aws-lambda-project", version = "v1"), servers = @Server(url = "/")) -public class SwaggerConfig {} diff --git a/aws-lambda-project/src/main/java/com/learning/awslambda/config/WebMvcConfig.java b/aws-lambda-project/src/main/java/com/learning/awslambda/config/WebMvcConfig.java deleted file mode 100644 index 1f7dbdb7..00000000 --- a/aws-lambda-project/src/main/java/com/learning/awslambda/config/WebMvcConfig.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.learning.awslambda.config; - -import lombok.RequiredArgsConstructor; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@Configuration -@RequiredArgsConstructor -public class WebMvcConfig implements WebMvcConfigurer { - private final ApplicationProperties properties; - - @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping(properties.getCors().getPathPattern()) - .allowedMethods(properties.getCors().getAllowedMethods()) - .allowedHeaders(properties.getCors().getAllowedHeaders()) - .allowedOriginPatterns(properties.getCors().getAllowedOriginPatterns()) - .allowCredentials(properties.getCors().isAllowCredentials()); - } -} diff --git a/aws-lambda-project/src/main/java/com/learning/awslambda/entities/Actor.java b/aws-lambda-project/src/main/java/com/learning/awslambda/entities/Actor.java index 8618d99d..d1a78aca 100644 --- a/aws-lambda-project/src/main/java/com/learning/awslambda/entities/Actor.java +++ b/aws-lambda-project/src/main/java/com/learning/awslambda/entities/Actor.java @@ -7,18 +7,10 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; import java.util.Objects; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; import org.hibernate.Hibernate; @Entity @Table(name = "actors") -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor public class Actor { @Id @@ -28,6 +20,29 @@ public class Actor { @Column(nullable = false) private String name; + public Actor(Long id, String name) { + this.id = id; + this.name = name; + } + + public Actor() {} + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/aws-lambda-project/src/main/java/com/learning/awslambda/model/request/ActorRequest.java b/aws-lambda-project/src/main/java/com/learning/awslambda/model/request/ActorRequest.java index c2e2857f..72204ad3 100644 --- a/aws-lambda-project/src/main/java/com/learning/awslambda/model/request/ActorRequest.java +++ b/aws-lambda-project/src/main/java/com/learning/awslambda/model/request/ActorRequest.java @@ -1,5 +1,3 @@ package com.learning.awslambda.model.request; -import jakarta.validation.constraints.NotEmpty; - -public record ActorRequest(@NotEmpty(message = "Name cannot be empty") String name) {} +public record ActorRequest(String name) {} diff --git a/aws-lambda-project/src/main/java/com/learning/awslambda/services/ActorService.java b/aws-lambda-project/src/main/java/com/learning/awslambda/services/ActorService.java index 72faab0c..1ae5aadb 100644 --- a/aws-lambda-project/src/main/java/com/learning/awslambda/services/ActorService.java +++ b/aws-lambda-project/src/main/java/com/learning/awslambda/services/ActorService.java @@ -1,22 +1,28 @@ package com.learning.awslambda.services; +import com.learning.awslambda.exception.ActorNotFoundException; import com.learning.awslambda.mapper.ActorMapper; import com.learning.awslambda.model.response.ActorResponse; import com.learning.awslambda.repositories.ActorRepository; -import java.util.Optional; -import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @Transactional(readOnly = true) -@RequiredArgsConstructor public class ActorService { private final ActorRepository actorRepository; private final ActorMapper actorMapper; - public Optional findActorByName(String name) { - return actorRepository.findByNameLike(name).map(actorMapper::toResponse); + public ActorService(ActorRepository actorRepository, ActorMapper actorMapper) { + this.actorRepository = actorRepository; + this.actorMapper = actorMapper; + } + + public ActorResponse findActorByName(String name) { + return actorRepository + .findByNameLike(name) + .map(actorMapper::toResponse) + .orElseThrow(() -> new ActorNotFoundException(name)); } } diff --git a/aws-lambda-project/src/main/java/com/learning/awslambda/web/controllers/ActorController.java b/aws-lambda-project/src/main/java/com/learning/awslambda/web/controllers/ActorController.java index aa200c85..8ba36eb4 100644 --- a/aws-lambda-project/src/main/java/com/learning/awslambda/web/controllers/ActorController.java +++ b/aws-lambda-project/src/main/java/com/learning/awslambda/web/controllers/ActorController.java @@ -1,9 +1,7 @@ package com.learning.awslambda.web.controllers; -import com.learning.awslambda.exception.ActorNotFoundException; import com.learning.awslambda.model.response.ActorResponse; import com.learning.awslambda.services.ActorService; -import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -12,16 +10,16 @@ @RestController @RequestMapping("/api/actors") -@RequiredArgsConstructor public class ActorController { private final ActorService actorService; + public ActorController(ActorService actorService) { + this.actorService = actorService; + } + @GetMapping("/{name}") public ResponseEntity getActorByName(@PathVariable String name) { - return actorService - .findActorByName(name) - .map(ResponseEntity::ok) - .orElseThrow(() -> new ActorNotFoundException(name)); + return ResponseEntity.ok(actorService.findActorByName(name)); } } diff --git a/aws-lambda-project/src/test/java/com/learning/awslambda/web/controllers/ActorControllerTest.java b/aws-lambda-project/src/test/java/com/learning/awslambda/web/controllers/ActorControllerTest.java index 1f60524b..17d65eaa 100644 --- a/aws-lambda-project/src/test/java/com/learning/awslambda/web/controllers/ActorControllerTest.java +++ b/aws-lambda-project/src/test/java/com/learning/awslambda/web/controllers/ActorControllerTest.java @@ -13,7 +13,6 @@ import com.learning.awslambda.services.ActorService; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -49,7 +48,7 @@ void setUp() { void shouldFindActorById() throws Exception { String actorId = "text"; ActorResponse actor = new ActorResponse(1L, "text 1"); - given(actorService.findActorByName(actorId)).willReturn(Optional.of(actor)); + given(actorService.findActorByName(actorId)).willReturn(actor); this.mockMvc .perform(get("/api/actors/{name}", actorId))