برنامه نویسی

API CRUD بدون سرور AWS Lambda با جاوا

AWS Lambda یک پلت فرم محاسباتی بدون سرور خدمات وب آمازون (AWS) است که به توسعه دهندگان اجازه می دهد تا کدهای خود را بدون ساخت یا مدیریت سرور اجرا کنند. جاوا یکی از محبوب ترین زبان های برنامه نویسی است که توسط AWS Lambda پشتیبانی می شود. با توانایی استفاده از جاوا، توسعه دهندگان می توانند از مهارت ها و کتابخانه های موجود خود برای ساخت و استقرار برنامه های بدون سرور بر روی پلت فرم AWS Lambda استفاده کنند.

توسعه دهندگان جاوا می توانند با ایجاد و اجرای توابع AWS Lambda مبتنی بر جاوا از انعطاف پذیری و مقیاس پذیری AWS Lambda بهره ببرند. این فرآیند شامل راه اندازی محیط مورد نیاز، نوشتن و آزمایش کد، و استقرار عملیات بر روی پلت فرم AWS Lambda است. با استفاده از جاوا در AWS Lambda، توسعه‌دهندگان می‌توانند به سرعت برنامه‌های بدون سرور را بسازند و مستقر کنند که هر ترافیکی را مدیریت می‌کنند.

در این مقاله توضیح خواهیم داد که چگونه می توانیم CRUD API را با پشته فناوری زیر در یک سناریوی عملی بسازیم.

  • جاوا 8
  • AWS Lambda
  • بدون سرور
  • DynamoDB

نیاز برای توسعه REST API

در این مقاله، ما توابع بدون سرور را برای پشتیبانی از الزامات زیر برای ذخیره مجموعه داده‌های نویسنده در جداول DynamoDB با پوشش توابع CRUD API توسعه خواهیم داد.

توضیحات تصویر

ساخت برنامه بدون سرور پایه

در این آموزش قصد داریم از CLI بدون سرور برای ایجاد اپلیکیشن و مدیریت زیرساخت API در مراحل بعدی استفاده کنیم.

ایجاد یک برنامه بدون سرور با زمان اجرا جاوا 8

در حال حاضر، بدون سرور از قالب های زیر پشتیبانی می کند:

  • aws-java-gradle
  • aws-java-maven

یک قالب جاوا maven یا gradle را به دلخواه انتخاب کنید. ما قصد داریم از برنامه جاوا مبتنی بر gradle استفاده کنیم.

$ serverless create --template aws-java-gradle --path aws-lambda-serverless-crud-java
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ساختار اولیه پروژه

توضیحات تصویر

  • بسته com.serverless – در اینجا ما همه منابع را نگه می داریم و این به عنوان بسته پایه برای پروژه عمل می کند.

  • serverless.yml – با این کار، می‌توانیم زیرساخت برنامه بدون سرور، مسیرهای API، منابع، متغیرهای محیطی، مجوزها و غیره را پیکربندی کنیم. اساساً، CLI بدون سرور از این فایل yml برای تنظیم دستورالعمل‌های تشکیل ابر برای این برنامه استفاده می‌کند.

  • Handler – می‌توانیم کنترل‌کننده‌هایی ایجاد کنیم و از serverless.yml با یک نقطه پایانی API (اختیاری) به آن‌ها اشاره کنیم. اساسا، کنترل کننده به عنوان نقطه شروع برای API بدون سرور عمل می کند.

پیکربندی توزیع ها و سایر تنظیمات برای استقرار – مرحله اختیاری

به طور پیش فرض برنامه بدون سرور توزیع را در build/distributions تحت نام hello.zip ایجاد می کند.

ما می توانیم این را تغییر دهیم و توزیع نهایی را به روشی که دوست داریم ایجاد و نامگذاری کنیم.

build.gradle را به صورت زیر در زیر کار buildZip تغییر دهید.

task buildZip(type: Zip) {
    archiveBaseName = "aws-lambda-serverless-crud-java"
    from compileJava
    from processResources
    into('lib') {
        from configurations.runtimeClasspath
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس مسیر توزیع را در serverless.yml تغییر دهید،

package:
  artifact: build/distributions/aws-lambda-serverless-crud-java.zip
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همچنین، می‌توانیم منطقه و مرحله برنامه‌ای را که قرار است این برنامه را اجرا کنیم، پیکربندی کنیم. با خیال راحت برنامه خود را با هر منطقه و مرحله ای ایجاد کنید.

provider:
  name: aws
  runtime: java8
  stage: development
  region: us-west-2
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

جداول DynamoDB و اجازه دسترسی از بدون سرور

در این مورد، ما 2 راه برای پیکربندی تنظیمات پایگاه داده و ایجاد مجوزها داریم که به صورت دستی و یک روش خودکار است که می توانیم به راحتی با استفاده از serverless.yml راه اندازی کنیم.

بیایید روی روش خودکاری که می توانیم از طریق serverless.yml پیکربندی کنیم تمرکز کنیم،

ابتدا باید جدول DynamoDB مورد نیاز خود را ایجاد کنیم و مجوزهایی را برای دسترسی به جدول از این برنامه بدون سرور اضافه کنیم. در اینجا ما از یک متغیر محیطی برای تنظیم جدول پایگاه داده استفاده می کنیم، زیرا زمانی که در مراحل بعدی به پایگاه داده دسترسی داشته باشیم، زندگی ما را آسان تر می کند.

provider:
  name: aws
  runtime: java8
  stage: development
  region: us-west-2

  environment:
    REGION: ${opt:region, self:provider.region}
    AUTHOR_TABLE: javatodev-author-${opt:stage, self:provider.stage}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس تعریف جدول،

resources:
  Resources:
    AuthorDynamoDBTable:
      Type: "AWS::DynamoDB::Table"
      Properties:
        BillingMode: PAY_PER_REQUEST
        AttributeDefinitions:
          - AttributeName: "id"
            AttributeType: "S"
        KeySchema:
          - AttributeName: "id"
            KeyType: "HASH"
        StreamSpecification:
          StreamViewType: "NEW_AND_OLD_IMAGES"
        TableName: ${self:provider.environment.AUTHOR_TABLE}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون تعاریفی را برای ایجاد جداول دینامو DB لازم در این برنامه ایجاد کرده ایم.

سپس باید مجوزهای لازم را برای استفاده از این جداول در فرآیندهای API برنامه بدهیم.

provider:
  name: aws
  runtime: java8
  stage: development
  region: us-west-2

  # ENVIRONMENT VARIABLES
  environment:
    REGION: ${opt:region, self:provider.region}
    AUTHOR_TABLE: javatodev-author-${opt:stage, self:provider.stage}

  # IAM ROLES TO ACCESS DYNAMODB TABLES
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:BatchGetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
      Resource:
        - !GetAtt AuthorDynamoDBTable.Arn
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در اینجا باید ARN صحیح را برای شناسایی جدول خود که با برنامه ایجاد شده است نشان دهیم. می توانیم با استفاده از آن اشاره کنیم !GetAtt AuthorDynamoDBTable.Arn.

توسعه API

اکنون می‌توانیم روی توسعه کنترل‌کننده‌های API و افشای آن‌ها از طریق HTTP API با AWS بدون سرور لامبدا تمرکز کنیم.

DTO / Utils و سایر کلاس ها

در این API، ما از یک کلاس Util جداگانه استفاده می کنیم که رشته بدن درخواست ورودی را با استفاده از Jackson ObjectMapper به java POJO تبدیل می کند.

package com.serverless.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.serverless.exception.IncomingRequestParsingException;

public class RequestConversionUtil {

    ObjectMapper objectMapper = new ObjectMapper();

    public <T> T parseRequestBody(String requestBodyContent, Class<T> outPutClass) {
        try {
            return objectMapper.readValue(requestBodyContent, outPutClass);
        } catch (JsonProcessingException e) {
            throw new IncomingRequestParsingException();
        }
    }

}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همچنین، 2 کلاس مدل اصلی وجود دارد که برای وارد کردن و خروج داده ها از API استفاده می کنیم.

package com.serverless.model;

public class AuthorDto {

    private String id;
    private String firstName;
    private String lastName;
    private String email;
    private String identificationNumber;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getIdentificationNumber() {
        return identificationNumber;
    }

    public void setIdentificationNumber(String identificationNumber) {
        this.identificationNumber = identificationNumber;
    }

    @Override public String toString() {
        return "AuthorDto{" +
            "id='" + id + '\'' +
            ", firstName="" + firstName + "\'' +
            ", lastName="" + lastName + "\'' +
            ", email="" + email + "\'' +
            ", identificationNumber="" + identificationNumber + "\'' +
            '}';
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

package com.serverless.model;

public class CommonAPIResponse {
    private String message;

    public CommonAPIResponse(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نقطه پایانی پایه API – GET

فقط یک پاسخ ساده JSON با یک درخواست ورودی.

functions:
  base_api:
    handler: com.serverless.Handler
    events:
      - httpApi:
          path: /
          method: get
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

package com.serverless;

import java.util.Collections;
import java.util.Map;

import org.apache.log4j.Logger;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

public class Handler implements RequestHandler<Map<String, Object>, ApiGatewayResponse> {

    private static final Logger LOG = Logger.getLogger(Handler.class);

    @Override
    public ApiGatewayResponse handleRequest(Map<String, Object> input, Context context) {
        Response responseBody = new Response("Go Serverless v1.x! Your function executed successfully!", input);
        return ApiGatewayResponse.builder()
                .setStatusCode(200)
                .setObjectBody(responseBody)
                .setHeaders(Collections.singletonMap("Content-Type", "application/json"))
                .build();
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نقطه پایانی API ایجاد نویسنده – POST

در اینجا می‌خواهیم یک نقطه پایانی API ایجاد کنیم که از یک روش POST HTTP پشتیبانی می‌کند که به ما امکان می‌دهد requestBody را با یک درخواست ورودی بیاوریم.

  author_registration:
    handler: com.serverless.author.RegistrationHandler
    events:
      - httpApi:
          path: /authors/registration
          method: post
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

package com.serverless.author;

import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.serverless.ApiGatewayResponse;
import com.serverless.Handler;
import com.serverless.model.AuthorDto;
import com.serverless.model.CommonAPIResponse;
import com.serverless.util.RequestConversionUtil;

import org.apache.log4j.Logger;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class RegistrationHandler implements RequestHandler<Map<String, Object>, ApiGatewayResponse> {

    private static final Logger LOG = Logger.getLogger(RegistrationHandler.class);
    private AmazonDynamoDB amazonDynamoDB;
    private String AUTHOR_DB_TABLE = System.getenv("AUTHOR_TABLE");
    private Regions REGION = Regions.fromName(System.getenv("REGION"));

    @Override public ApiGatewayResponse handleRequest(Map<String, Object> input, Context context) {
        RequestConversionUtil requestConversionUtil = new RequestConversionUtil();
        AuthorDto request = requestConversionUtil.parseRequestBody(input.get("body").toString(), AuthorDto.class);
        LOG.info("Incoming author registration request "+request.toString());
        this.initDynamoDbClient();
        persistData(request);
        return ApiGatewayResponse.builder()
            .setStatusCode(201)
            .setHeaders(Collections.singletonMap("Content-Type", "application/json"))
            .setObjectBody(new CommonAPIResponse("Author registration successfully completed."))
            .build();
    }

    private String persistData(AuthorDto request) throws ConditionalCheckFailedException {
        String user_id = UUID.randomUUID().toString();
        Map<String, AttributeValue> attributesMap = new HashMap<>();
        attributesMap.put("id", new AttributeValue(user_id));
        attributesMap.put("firstName", new AttributeValue(request.getFirstName()));
        attributesMap.put("lastName", new AttributeValue(request.getLastName()));
        attributesMap.put("email", new AttributeValue(request.getEmail()));
        attributesMap.put("identification_number", new AttributeValue(request.getIdentificationNumber()));
        amazonDynamoDB.putItem(AUTHOR_DB_TABLE, attributesMap);
        return user_id;
    }

    private void initDynamoDbClient() {
        this.amazonDynamoDB = AmazonDynamoDBClientBuilder.standard()
            .withRegion(REGION)
            .build();
    }

}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

خواندن متغیرهای محیط در AWS Lambda Java

در این API ما قصد داریم REGION و نام جدول را از متغیرهای محیطی بخوانیم. اگر در آینده مجبور به تغییر نام جدول باشیم، این زندگی توسعه دهنده را آسان تر می کند.

private String AUTHOR_DB_TABLE = System.getenv("AUTHOR_TABLE");
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ارسال پاسخ JSON از AWS Lambda Java

به طور پیش‌فرض، همه پاسخ‌ها از APIهای لامبدا AWS با استفاده از نوع محتوای ساده/متن ارسال می‌شوند. از آنجایی که باید همه پاسخ‌ها را به‌عنوان JSON برای مصرف‌کنندگان ارسال کنیم، باید سرصفحه‌های Content-type: application/json را روی همه پاسخ‌های API تنظیم کنیم.

.setHeaders(Collections.singletonMap("Content-Type", "application/json"))
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نویسنده API Endpoint را با FindAll و FindById بخوانید – GET

  author_reads:
    handler: com.serverless.author.ReadHandler
    events:
      - httpApi:
          path: /authors
          method: get
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

package com.serverless.author;

import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.GetItemRequest;
import com.amazonaws.services.dynamodbv2.model.GetItemResult;
import com.amazonaws.services.dynamodbv2.model.ScanRequest;
import com.amazonaws.services.dynamodbv2.model.ScanResult;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.serverless.ApiGatewayResponse;
import com.serverless.model.AuthorDto;
import com.serverless.model.CommonAPIResponse;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ReadHandler implements RequestHandler<APIGatewayProxyRequestEvent, ApiGatewayResponse> {

    private AmazonDynamoDB amazonDynamoDB;
    private String AUTHOR_DB_TABLE = System.getenv("AUTHOR_TABLE");
    private Regions REGION = Regions.fromName(System.getenv("REGION"));


    @Override public ApiGatewayResponse handleRequest(APIGatewayProxyRequestEvent input, Context context) {
        this.initDynamoDbClient();
        Map<String, String> queryParams = input.getQueryStringParameters();

        if (queryParams != null && queryParams.containsKey("findAll") && Boolean.parseBoolean(queryParams.get("findAll"))) {

            //Find All
            Map<String, AttributeValue> lastKeyEvaluated = null;
            List<AuthorDto> authorDtos = new ArrayList<>();
            do {
                ScanRequest scanRequest = new ScanRequest()
                    .withTableName(AUTHOR_DB_TABLE)
                    .withLimit(10)
                    .withExclusiveStartKey(lastKeyEvaluated);
                ScanResult result = amazonDynamoDB.scan(scanRequest);
                for (Map<String, AttributeValue> item : result.getItems()) {
                    authorDtos.add(mapToDto(item));
                }
                lastKeyEvaluated = result.getLastEvaluatedKey();
            } while (lastKeyEvaluated != null);

            return ApiGatewayResponse.builder()
                .setHeaders(Collections.singletonMap("Content-Type", "application/json"))
                .setObjectBody(authorDtos).setStatusCode(200).build();

        } else if (queryParams!= null && queryParams.containsKey("id") && queryParams.get("id") != null) {

            //Find by id
            Map<String, AttributeValue> attributesMap = new HashMap<>();
            attributesMap.put("id", new AttributeValue(queryParams.get("id")));
            GetItemRequest getItemRequest = new GetItemRequest().withTableName(AUTHOR_DB_TABLE)
                .withKey(attributesMap);
            GetItemResult item = amazonDynamoDB.getItem(getItemRequest);

            return ApiGatewayResponse.builder()
                .setHeaders(Collections.singletonMap("Content-Type", "application/json"))
                .setObjectBody(mapToDto(item.getItem())).setStatusCode(200).build();

        }

        return ApiGatewayResponse.builder()
            .setHeaders(Collections.singletonMap("Content-Type", "application/json"))
            .setObjectBody(new CommonAPIResponse("No data found under given query"))
            .setStatusCode(200).build();

    }

    private AuthorDto mapToDto(Map<String, AttributeValue> item) {
        AuthorDto authorDto = new AuthorDto();
        authorDto.setId(item.get("id").getS());
        authorDto.setEmail(item.get("email").getS());
        authorDto.setFirstName(item.get("firstName").getS());
        authorDto.setLastName(item.get("lastName").getS());
        authorDto.setIdentificationNumber(item.get("identification_number").getS());
        return authorDto;
    }

    private void initDynamoDbClient() {
        this.amazonDynamoDB = AmazonDynamoDBClientBuilder.standard()
            .withRegion(REGION)
            .build();
    }

}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

استفاده از پارامترهای پرس و جو با AWS Lambda Java

در اینجا باید یک پارامتر پرس و جو بیاوریم تا مشخص شود کاربران درخواست خواندن از DB برای جابجایی بین findAll و findById را دارند.

در این مورد، می‌توانیم از APIGatewayProxyRequestEvent که با کتابخانه هسته AWS بسته می‌شود، استفاده کنیم تا این پارامترها را به راحتی از درخواست‌های دریافتی ضبط کنیم.

Map<String, String> queryParams = input.getQueryStringParameters();
queryParams.get("findAll");
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

به‌روزرسانی نقطه پایانی نویسنده – PATCH

  author_update:
    handler: com.serverless.author.UpdateHandler
    events:
      - httpApi:
          path: /authors/{id}
          method: patch
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در اینجا ما requestBody و author id را به عنوان پارامترهای مسیر می آوریم. همانطور که در نقطه پایانی READ انجام دادیم، می‌توانیم هر دو را با استفاده از APIGatewayProxyRequestEvent ضبط کنیم.

package com.serverless.author;

import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.AttributeAction;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.AttributeValueUpdate;
import com.amazonaws.services.dynamodbv2.model.UpdateItemRequest;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.serverless.ApiGatewayResponse;
import com.serverless.model.AuthorDto;
import com.serverless.model.CommonAPIResponse;
import com.serverless.util.RequestConversionUtil;

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

public class UpdateHandler implements RequestHandler<APIGatewayProxyRequestEvent, ApiGatewayResponse> {
    private AmazonDynamoDB amazonDynamoDB;
    private String AUTHOR_DB_TABLE = System.getenv("AUTHOR_TABLE");
    private Regions REGION = Regions.fromName(System.getenv("REGION"));

    @Override public ApiGatewayResponse handleRequest(APIGatewayProxyRequestEvent input, Context context) {
        initDynamoDbClient();
        RequestConversionUtil requestConversionUtil = new RequestConversionUtil();
        AuthorDto request = requestConversionUtil.parseRequestBody(input.getBody(), AuthorDto.class);

        Map<String, AttributeValue> keyMap = new HashMap<>();
        keyMap.put("id", new AttributeValue(input.getPathParameters().get("id")));

        UpdateItemRequest updateItemRequest = new UpdateItemRequest()
            .withTableName(AUTHOR_DB_TABLE)
            .addKeyEntry("id", new AttributeValue(input.getPathParameters().get("id")))
            .addAttributeUpdatesEntry("firstName",
                new AttributeValueUpdate(
                    new AttributeValue(request.getFirstName()),
                    AttributeAction.PUT))
            .addAttributeUpdatesEntry("lastName",
                new AttributeValueUpdate(
                    new AttributeValue(request.getLastName()),
                    AttributeAction.PUT))
            .addAttributeUpdatesEntry("email",
                new AttributeValueUpdate(
                    new AttributeValue(request.getEmail()),
                    AttributeAction.PUT))
            .addAttributeUpdatesEntry("identification_number",
                new AttributeValueUpdate(
                    new AttributeValue(request.getIdentificationNumber()),
                    AttributeAction.PUT));

        amazonDynamoDB.updateItem(updateItemRequest);

        return ApiGatewayResponse.builder()
            .setHeaders(Collections.singletonMap("Content-Type", "application/json"))
            .setObjectBody(new CommonAPIResponse("Author update successfully completed")).build();
    }

    private void initDynamoDbClient() {
        this.amazonDynamoDB = AmazonDynamoDBClientBuilder.standard()
            .withRegion(REGION)
            .build();
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Delete Author API Endpoint – DELETE

  author_delete:
    handler: com.serverless.author.DeleteHandler
    events:
      - httpApi:
          path: /authors/{id}
          method: delete
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

package com.serverless.author;

import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.DeleteItemRequest;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.serverless.ApiGatewayResponse;
import com.serverless.model.CommonAPIResponse;

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

public class DeleteHandler implements RequestHandler<APIGatewayProxyRequestEvent, ApiGatewayResponse> {
    private AmazonDynamoDB amazonDynamoDB;
    private String AUTHOR_DB_TABLE = System.getenv("AUTHOR_TABLE");
    private Regions REGION = Regions.fromName(System.getenv("REGION"));

    @Override public ApiGatewayResponse handleRequest(APIGatewayProxyRequestEvent input, Context context) {
        initDynamoDbClient();

        Map<String, AttributeValue> keyMap = new HashMap<>();
        keyMap.put("id", new AttributeValue(input.getPathParameters().get("id")));

        DeleteItemRequest request = new DeleteItemRequest()
            .withTableName(AUTHOR_DB_TABLE)
            .withKey(keyMap);
        amazonDynamoDB.deleteItem(request);

        return ApiGatewayResponse.builder()
            .setHeaders(Collections.singletonMap("Content-Type", "application/json"))
            .setObjectBody(new CommonAPIResponse("Author deletion successfully completed")).build();

    }

    private void initDynamoDbClient() {
        this.amazonDynamoDB = AmazonDynamoDBClientBuilder.standard()
            .withRegion(REGION)
            .build();
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در نهایت، serverless.yml تکمیل شده باید مانند زیر باشد، مطمئن شوید که تنظیمات yml را در سطح صحیح نوشته‌اید.

service: aws-lambda-serverless-crud-java

frameworkVersion: '3'

provider:
  name: aws
  runtime: java8
  stage: development
  region: us-west-2

  # ENVIRONMENT VARIABLES
  environment:
    REGION: ${opt:region, self:provider.region}
    AUTHOR_TABLE: javatodev-author-${opt:stage, self:provider.stage}

  # IAM ROLES TO ACCESS DYNAMODB TABLES
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:BatchGetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
      Resource:
        - !GetAtt AuthorDynamoDBTable.Arn

resources:
  Resources:
    AuthorDynamoDBTable:
      Type: "AWS::DynamoDB::Table"
      Properties:
        BillingMode: PAY_PER_REQUEST
        AttributeDefinitions:
          - AttributeName: "id"
            AttributeType: "S"
        KeySchema:
          - AttributeName: "id"
            KeyType: "HASH"
        StreamSpecification:
          StreamViewType: "NEW_AND_OLD_IMAGES"
        TableName: ${self:provider.environment.AUTHOR_TABLE}

package:
  artifact: build/distributions/aws-serverless-crud-java.zip

functions:
  base_api:
    handler: com.serverless.Handler
    events:
      - httpApi:
          path: /
          method: get
  author_registration:
    handler: com.serverless.author.RegistrationHandler
    events:
      - httpApi:
          path: /authors/registration
          method: post
  author_reads:
    handler: com.serverless.author.ReadHandler
    events:
      - httpApi:
          path: /authors
          method: get
  author_update:
    handler: com.serverless.author.UpdateHandler
    events:
      - httpApi:
          path: /authors/{id}
          method: patch
  author_delete:
    handler: com.serverless.author.DeleteHandler
    events:
      - httpApi:
          path: /authors/{id}
          method: delete
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون همه کار انجام شده است، ما کل API را با نمایان شدن نقطه پایانی API لازم نوشته ایم. ما می توانیم API را در AWS lambda مستقر کنیم.

$ serverless deploy
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

خروجی API Deployment از AWS Lambda Serverless
عملکرد AWS Lambda در داشبورد AWS
پایگاه داده DynamoDB ایجاد شده در AWS
مجوزهایی در AWS Lambda برای دسترسی به جداول DyanmoDB اضافه شد.

تست های API

ما از مجموعه Postman برای آزمایش این تنظیمات API استفاده می کنیم. می توانید مجموعه Postman را با این لینک همگام کنید.

توضیحات تصویر

توضیحات تصویر

نتیجه گیری

در این مقاله، نحوه ساخت API بدون سرور با استفاده از جاوا و DynamoDB و استقرار با AWS lambda را مورد بحث قرار داده ایم.

پیاده سازی همه این مثال ها و قطعه کد را می توان در مخزن GitHub ما یافت.

کد نویسی مبارک

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا