3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RCC (立命館コンピュータークラブ)Advent Calendar 2024

Day 1

Qiita AdventCalender2024に投稿してクリスマスツリーを成長 & 飾り付けさせよう! Part1 バック & AWS デプロイ編[QiitaAPIを使った簡単なHTTPAPIをLambda & APIGatewayにデプロイしよう]

Last updated at Posted at 2024-12-01

みなさんついにQiitaAdventCalender2024が始まりました!私はここから25日間毎日記事投稿する...というわけですが(吐きそう)...12/1でDay1ということで何を書こうかなと考え,12/1の朝にQiitaAdventCalender2024に関連した作品を作ろうと思いました.しかし12/1の朝に思い立ったのでなんとかして1日でフロントエンドとAPI叩く用のLambda関数を作成し,フロントの静的ファイルをS3にホスティングしてCloudFrontで配信し,Lambda関数をAPIGatewayで受け付けるデプロイ処理もしつつ,この記事も書かないといけないのでガバもあると思います.その際は遠慮なくコメントで突っ込んでください.12/25までにより良くしていこうと思います.また,作品の制作レポートだけではちょっとなんとも言えないのでAWS LambdaとAmazon API Gatewayを使用して,Qiita APIと連携するシステムの構築方法について解説もしようと思う.

完成(?)画像

スクリーンショット 2024-12-01 22.28.46.png

まだ1記事もないのでまっさら(植木鉢)のみですが25記事投稿したらすごいことになる...はずです.12/24 12/25に完成したシステムのレポートとフロント部の解説をします.今回はバックエンド(Lambda関数)部分のみです.

作ったシステムの概要

本システムは以下の機能を提供する.

  • 指定したユーザーIDの記事を検索
  • 2024年12月1日から12月25日までの期間で投稿された記事を取得
  • 記事のタイトル,URL,投稿日時などの情報を返す
  • 後にこのレスポンスをフロントでどう使うか考える

一旦フロントでは記事の数をカウントするのみにします

AWSアーキテクチャはこんな感じです
スクリーンショット 2024-12-02 0.35.43.png

実装手順

1. Qiita APIのアクセストークン取得
Qiitaの設定画面からQiitaAPIのアクセストークンを発行する.

スクリーンショット 2024-12-01 23.19.31.png

2. AWS Lambdaの設定
バックエンド(API叩くのみ)はPythonで実装します.

  • Python 3.xのランタイムで新規Lambda関数を作成
    スクリーンショット 2024-12-01 23.21.41.png

「関数を作成」を押して一旦作成してください

  • 環境変数QIITA_ACCESS_TOKENに1で作成したQiitaのアクセストークンを設定
    スクリーンショット 2024-12-01 23.22.44.png

3. ローカルでPythonプロジェクトを作成
まずディレクトリを作成

mkdir lambda_function
cd lambda_function

pythonファイルを作成

touch lambda.py

以下のように実装.QiitaID(user_id)はフロントからクエリパラメータとして待ち受ける.

lambda.py
import os
import json
import requests

def lambda_handler(event, context):
    try:
        # クエリパラメータからuser_idを取得
        user_id = event.get('queryStringParameters', {}).get('user_id')

        if not user_id or not isinstance(user_id, str):
            return {
                'statusCode': 400,
                'body': json.dumps({
                    'count': 0,
                    'message': 'user_id is required'
                })
            }

        qiita_access_token = os.environ.get('QIITA_ACCESS_TOKEN')
        if not qiita_access_token:
            raise Exception('QIITA_ACCESS_TOKEN is not configured')

        per_page = 100
        page = 1

        headers = {
            'Content-Type': 'application/json',
            'Authorization': f'Bearer {qiita_access_token}'
        }

        query_params = {
            'page': str(page),
            'per_page': str(per_page),
            'query': f'user:{user_id} created:>=2024-12-01 created:<=2024-12-15'
        }

        url = 'https://qiita.com/api/v2/items'
        response = requests.get(url, headers=headers, params=query_params)

        if not response.ok:
            error_text = response.text
            raise Exception(f'Failed to fetch data from Qiita API: {response.status_code} {error_text}')

        data = response.json()

        return {
            'statusCode': 200,
            'headers': {
                'Content-Type': 'application/json'
            },
            'body': json.dumps({
                'count': len(data),
                'articles': [
                    {
                        'id': article['id'],
                        'title': article['title'],
                        'userId': article['user']['id'],
                        'userName': article['user']['name'],
                        'created_at': article['created_at'],
                        'updated_at': article['updated_at'],
                        'url': article['url']
                    } for article in data
                ]
            })
        }

    except Exception as error:
        print('Error details:', error)
        return {
            'statusCode': 500,
            'body': json.dumps({
                'count': 0,
                'message': str(error) or 'Internal Server Error'
            })
        }

依存関係を定義するrequirements.txtを作成

touch requirements.txt

以下のように記述

requirements.txt
requests==2.28.2

その後以下のコマンドでプロジェクトに依存関係をインストール

pip install --target ./packages -r requirements.txt

最後にプロジェクトごとzip化する.

zip -r ../zip_lambda_deploy .

4. Lambdaにzipをアップロード
スクリーンショット 2024-12-01 23.29.25.png

作成した関数を選択して,「コード」→「アップロード元」→「.zipファイル」を選択し,3で作成したzipをアップロードする.

Lambdaはこれで自動で更新されるのでOK

4. APIGatewayでLambda関数を待ち受ける
APIGatewayのホームから「APIを作成」を選択し,「HTTP API」を「構築」する.

スクリーンショット 2024-12-01 23.33.29.png

色々設定があるが特に何も設定しなくてもOK.API名のみ何か考える.
スクリーンショット 2024-12-01 23.34.26.png

Lambda関数にアクセスするためのエンドポイントを指定するため,まず「ルート」で「作成」を選択
スクリーンショット 2024-12-01 23.36.24.png

GETやPOSTやANYといったメソッドで設定するエンドポイントで使用すものを選択し,エンドポイント名を入力する.
スクリーンショット 2024-12-01 23.36.39.png
エンドポイントを作成したらLambda関数を統合するために「統合をアタッチする」を選択する.
スクリーンショット 2024-12-01 23.37.31.png
統合タイプを「Lambda関数」にしてリージョンと統合するLambda関数を選択する.
スクリーンショット 2024-12-01 23.38.15.png
最後にCORSを設定する.「Access-Control-Access-Origin」を選択し,フロントエンドのURLを入力する.

一旦localhostや*にしてもいいがセキュリティ上後で正しいフロントURLを入力しよう.

スクリーンショット 2024-12-01 23.38.41.png

これでOK!APIGatewayは何も設定していなければ自動デプロイできる.

作成したAPIのリンクを確認

作成したLambda関数を見るとAPIGatewayが存在するのでAPIGatewayをクリックするとAPIエンドポイントがいる.これをフロントで使用すればOK
スクリーンショット 2024-12-01 23.44.49.png

フロントでどう使うのか

こんな感じでフロントで使えばいい.フロントの詳細はPart2(2024/12/24)で語ります.

const fetchArticleCount = async () => {
    try {
      setLoading(true);
      const response = await fetch(`https://APIGatewayのAPIエンドポイント?user_id=${encodeURIComponent(userId)}`);
      const data = await response.json();
    } catch (error) {
      console.error(error);
    } finally {
    // ...
    }
  };

今回は簡単なAPI作成をLambdaとAPIGatewayでデプロイしました.フロントエンドエンジニアの方も簡単なAPIを使いたいことがあると思うのでぜひAWSを使って簡単なAPIをデプロイしてフロントエンドの開発に活用しましょう!

今回作成したアプリはこちらから.ぜひ使ってみてください!
Qiita AdventCalender 2024 ChristmasTree

それでは今日のクリスマスツリーです.
スクリーンショット 2024-12-01 22.28.46.png

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?