[AWS Application Composer] 簡単GUIでIaCに変換できる新AWSサービス紹介

## はじめに
バックエンドエンジニアやってます、@funada-akihiro です。

本記事は、 [mediba Advent カレンダー2022](https://qiita.com/advent-calendar/2022/mediba) の9日目の記事になります。

この時期になると行われるイベントがあります！
それは・・・[AWS re:Invent](https://reinvent.awsevents.com/)です。

イベントの中で発表された、最新アップデートの中で気になったものを今回ご紹介させていただきます！

## AWS Application Composer

![スクリーンショット 2022-12-04 20.21.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960827/d7173a9d-81fc-9bb8-247c-49c0e20127a3.png)
(こちらの画像は、https://aws.amazon.com/jp/about-aws/whats-new/2022/12/aws-application-composer-preview/ より引用)

## できること
1. 新しいサーバーレスアプリケーションの設計と構築
2. IaCを介してアプリケーションを管理
3. アプリケーションのアーキテクチャと構成を視覚化

(https://aws.amazon.com/jp/application-composer/ より引用)

## 触ってみた
### canvas
- 左のメニューから利用したいAWSリソースをキャンバス上にドラック&ドロップ
- キャンバス上のAWSリソースをクリックして、Detailsで細かな設定

![スクリーンショット 2022-12-04 21.10.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960827/e0edcd16-7fc9-458e-5641-44e9ddfaa918.png)

### template
- キャンバスに描画したAWSリソースをSAMテンプレートとして出力
- テンプレートファイルを直接編集可能

```
Transform: AWS::Serverless-2016-10-31
Resources:
  UserFunction:
    Type: AWS::Serverless::Function
    Properties:
      Description: !Sub
        - Stack ${AWS::StackName} Function ${ResourceName}
        - ResourceName: UserFunction
      CodeUri: src/UserFunction
      Handler: handler.handler
      Runtime: python3.8
      MemorySize: 3008
      Timeout: 30
      Tracing: Active
      Layers:
        - layer
      Environment:
        Variables:
          TABLE_NAME: !Ref UserTable
          TABLE_ARN: !GetAtt UserTable.Arn
          TABLE_NAME_2: !Ref UserTable
          TABLE_ARN_2: !GetAtt UserTable.Arn
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref UserTable
        - DynamoDBCrudPolicy:
            TableName: !Ref UserTable
      Events:
        RestApiGETuser:
          Type: Api
          Properties:
            Path: /user
            Method: GET
            RestApiId: !Ref RestApi
  UserFunctionLogGroup:
    Type: AWS::Logs::LogGroup
    DeletionPolicy: Retain
    Properties:
      LogGroupName: !Sub /aws/lambda/${UserFunction}
  UserTable:
    Type: AWS::DynamoDB::Table
    Properties:
      AttributeDefinitions:
        - AttributeName: uid
          AttributeType: S
        - AttributeName: timestamp
          AttributeType: S
      BillingMode: PAY_PER_REQUEST
      KeySchema:
        - AttributeName: uid
          KeyType: HASH
        - AttributeName: timestamp
          KeyType: RANGE
      StreamSpecification:
        StreamViewType: NEW_AND_OLD_IMAGES
  S3Function:
    Type: AWS::Serverless::Function
    Properties:
      Description: !Sub
        - Stack ${AWS::StackName} Function ${ResourceName}
        - ResourceName: S3Function
      CodeUri: src/S3Function
      Handler: handler.handler
      Runtime: python3.8
      MemorySize: 3008
      Timeout: 30
      Tracing: Active
      Layers:
        - layer
      Environment:
        Variables:
          BUCKET_NAME: !Ref imgBucket
          BUCKET_ARN: !GetAtt imgBucket.Arn
      Policies:
        - S3CrudPolicy:
            BucketName: !Ref imgBucket
      Events:
        RestApiGETimg:
          Type: Api
          Properties:
            Path: /img
            Method: GET
            RestApiId: !Ref RestApi
  S3FunctionLogGroup:
    Type: AWS::Logs::LogGroup
    DeletionPolicy: Retain
    Properties:
      LogGroupName: !Sub /aws/lambda/${S3Function}
  imgBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub ${AWS::StackName}-imgbucket-${AWS::AccountId}
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: aws:kms
              KMSMasterKeyID: alias/aws/s3
      PublicAccessBlockConfiguration:
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
  imgBucketBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref imgBucket
      PolicyDocument:
        Id: RequireEncryptionInTransit
        Version: '2012-10-17'
        Statement:
          - Principal: '*'
            Action: '*'
            Effect: Deny
            Resource:
              - !GetAtt imgBucket.Arn
              - !Sub ${imgBucket.Arn}/*
            Condition:
              Bool:
                aws:SecureTransport: 'false'
  RestApi:
    Type: AWS::Serverless::Api
    Properties:
      Name: !Sub
        - ${ResourceName} From Stack ${AWS::StackName}
        - ResourceName: RestApi
      StageName: Prod
      DefinitionBody:
        openapi: '3.0'
        info: {}
        paths:
          /user:
            get:
              x-amazon-apigateway-integration:
                httpMethod: POST
                type: aws_proxy
                uri: !Sub arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${UserFunction.Arn}/invocations
              responses: {}
          /img:
            get:
              x-amazon-apigateway-integration:
                httpMethod: POST
                type: aws_proxy
                uri: !Sub arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${S3Function.Arn}/invocations
              responses: {}
      EndpointConfiguration: REGIONAL
      TracingEnabled: true
  layer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      Description: !Sub
        - Stack ${AWS::StackName} Layer ${ResourceName}
        - ResourceName: layer
      ContentUri: src/Layer
      RetentionPolicy: Retain
    Metadata:
      BuildMethod: python3.8
```
## 感想
サクッとSAMテンプレートを作成することができました。
細かな設定は、後からテンプレートを修正すれば問題ないので、少し微妙な記述になっていても気にしない！
サーバレスアプリケーションの新規開発が加速すること間違いなしです。

## さいごに

現在、medibaの募集求人ページから応募され入社が決定すると、お祝い金として30万円をプレゼントするキャンペーンを実施中です！！
リモート環境を充実のためディスプレイやマイク等を買いそろえるも良し。スキル習熟のために自己研鑽に使うも良し。使途は完全自由です。

[→　募集・応募ページ](https://hrmos.co/pages/mediba/jobs/1100000001)

いきなり応募だとちょっとハードルが高い・・でも興味がある方は、カジュアル面談も行っていますので、まずはお話してみませんか？

[→　カジュアル面談](https://hrmos.co/pages/mediba/jobs/6100000001)

※お祝い金は、試用期間（3か月）を経て、雇用が継続した場合に支給させて頂きます。