BFT名古屋 TECH BLOG

日々の業務で得た知識を所属するエンジニアたちがアウトプットしていきます。

【AWS, Python】RESTful API 作ってみた!Lambda実装編

AWS,RESTfulAPI,Lambda

はじめに

こんにちは~、BFT名古屋支店の猫です。季節の変わり目のせいか、毎日眠いです。
そんな眠たい時でもできるのが、そう、検証!

ということで、"RESTful APIの構築" をやってみました。

使用したのは「Amazon API Gateway」「AWS Lambda」「Amazon RDS」の3つです。
これらを選択した理由は、業務で扱ったことがあり取り組みやすかった&ざっと調べた感じ情報が色々落ちてそうと思ったためです。ありがとうインターネット!

今回はLambdaの実装部分を中心にご紹介します。
API GatewayとLambdaの連携が上手くいかない」「LambdaとRDSの連携が上手くいかない」といった方の参考になればと思います。

この記事を読むのにあるといい知識

APIの概要

ここでは作ったAPIの構成や機能についてご紹介します。
あまり興味ない方は飛ばしていただいてOKです。

今回は、「料理のレシピを登録・更新・削除・閲覧できるAPI 」を作りました。理由は特にありません。

構成イメージ

構成

誰が何をしているのかを簡単にご説明します。

  • Amazon API Gateway
    ユーザからのリクエストを受け取って、中間処理を実行し、ユーザにレスポンスを返します。
    中間処理は、リソース(ex:/recipes, /recipes/{id})やメソッド(ex:GET, POST, DELETE, …)ごとに定義することができます。今回の構成ではLambdaを呼び出します。

    実際の画面

  • AWS Lambda
    API Gatewayから呼び出されると、所定の処理を実行し、結果をAPI Gatewayに返します。
    今回作成したLambdaでは「リクエストに応じてSQL文を生成し、RDSに対してクエリを実行する」という処理を実行します。

  • Amazon RDS
    登録されているデータ(=料理のレシピ)を持っています。
    Lambdaから投げられたSQL文を実行し、その結果をLambdaに返します。

  

機能

どんな機能があるのか簡単にご説明します。
データベース処理として一般的なCRUD(Create, Read, Update, Delete)の機能を実装しています。

  • 登録機能
    レシピをデータベースに登録する

  • 更新機能
    idで指定されたレシピを更新する

  • 削除機能
    idで指定されたレシピを削除する

  • 閲覧機能(全レシピ)
    データベースに登録されているすべてのレシピを表示する

  • 閲覧機能(id指定)
    idで指定されたレシピを表示する

Lambdaの実装

ではさっそく実装したコードを紹介していきます。
実装のポイントは以下の二点です。

  • API Gatewayから連携されたリクエストの、bodyやパスパラメータを抽出していること
  • pymysqlというモジュールを使って、RDSへの接続やクエリ実行処理を実装していること

これらについて、詳しくははまた別の記事にまとめたいと思いますので
今日のところは(ふ~ん、こんな書き方するんだ~)くらいに思っていただければと思います。

使用環境

  • AWS Lambda
  • Python 3.9
  • pymysql ライブラリ

登録機能

レシピをDBに登録する機能です。
リクエストbodyで指定されたレシピをDBに登録し、登録できた場合はそのレコードを、登録できなかった(リクエストの形式がおかしかったなど)場合はエラー文を返します。

大まかな流れは以下の通りです。
1. DB接続
2. レコード登録
3. レコード取得(登録したレコードを取得)
4. レスポンス生成

更新機能

DBに登録されているレシピを更新する機能です。
リクエストのパスパラメータで指定されたidのレコードに対して、 リクエストbodyで指定された項目の値を更新します。
更新できた場合はそのレコードを、更新できなかった(指定されたidのレコードが存在しないなど)場合はエラー文を返します。

大まかな流れは以下の通りです。
1. DB接続
2. 存在確認(指定されたidのレコードがDBに存在するか確認)
3. レコード更新
4. レコード取得(更新したレコードを取得)
5. レスポンス生成

削除機能

DBに登録されているレシピを削除する機能です。
リクエストのパスパラメータで指定されたidのレコードをデータベースから削除します。
削除できた場合はその旨を伝えるメッセージを、削除できなかった(指定されたidのレコードが存在しないなど)場合はエラー文を返します。

大まかな流れは以下の通りです。
1. DB接続
2. 存在確認(指定されたidのレコードがDBに存在するか確認)
3. レコード削除
4. レスポンス生成

閲覧機能(全レシピ)

DBに登録されている全レコードを取得する機能です。
取得できた場合はそのレコードを、取得できなかった(レコードが存在しないなど)場合はエラー文を返します。

大まかな流れは以下の通りです。
1. DB接続
2. レコード取得(全レコードを取得)
3. レスポンス生成

閲覧機能(id指定)

先ほどご紹介した「閲覧機能(全レシピ)」のid指定するバージョンです。
リクエストのパスパラメータで指定されたidのレコードのみを取得します。
取得できた場合はそのレコードを、取得できなかった(指定されたidのレコードが存在しないなど)場合はエラー文を返します。

大まかな流れは以下の通りです。
1. DB接続
2. レコード取得(指定されたidのレコードのみを取得)
3. レスポンス作成

使ってみた

できあがったAPIを使ってみました!
今回は画面を作っていないので、curlコマンドを使用してAPIを叩きます。

①まずはデータベースが空っぽであることを確認します。

[myuser@myhost ~]$ curl -X GET https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/my-recipe-prod/recipes | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    15  100    15    0     0    269      0 --:--:-- --:--:-- --:--:--   272
{
  "recipes": []
}
[myuser@myhost ~]$

データが登録されていないことが確認できました。

②次にデータを登録してみます。

[myuser@myhost ~]$ curl -X POST -H "Content-Type: application/json" -d '{"title":"カレー", "making_time":"40分", "serves":"4人", "ingredients":"肉,玉ねぎ,人
参,スパイス,水", "cost":1000'  https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/my-recipe-prod/recipes | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   451  100   322  100   129    767    307 --:--:-- --:--:-- --:--:--  1076
{
  "message": "Recipe successfully created!",
  "recipe": [
    {
      "id": 1,
      "title": "カレー",
      "making_time": "40分",
      "serves": "4人",
      "ingredients": "肉,玉ねぎ,人参,スパイス,水",
      "cost": 1000,
      "created_at": "2022-10-12 05:00:21",
      "updated_at": "2022-10-12 05:00:21"
    }
  ]
}
[myuser@myhost ~]$

登録が成功したことを示すメッセージが出力されました!
このあと同様に2つほど登録しました。

③登録したデータを見てみます。
こちらは全レシピを閲覧するリクエストとその結果です。
データを3つ登録したので、3つのデータが出力されれば成功です。

[myuser@myhost ~]$ curl -X GET https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/my-recipe-prod/recipes | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   772  100   772    0     0  15858      0 --:--:-- --:--:-- --:--:-- 16083
{
  "recipes": [
    {
      "id": 1,
      "title": "カレー",
      "making_time": "40分",
      "serves": "4人",
      "ingredients": "肉,玉ねぎ,人参,スパイス,水",
      "cost": 1000,
      "created_at": "2022-10-12 05:00:21",
      "updated_at": "2022-10-12 05:00:21"
    },
    {
      "id": 2,
      "title": "スープ",
      "making_time": "15分",
      "serves": "2人",
      "ingredients": "トマト,ツナ,コンソメ,水",
      "cost": 300,
      "created_at": "2022-10-12 05:22:57",
      "updated_at": "2022-10-12 05:22:57"
    },
    {
      "id": 3,
      "title": "だし巻き卵",
      "making_time": "5分",
      "serves": "2人",
      "ingredients": "卵,だし,水",
      "cost": 150,
      "created_at": "2022-10-12 05:24:36",
      "updated_at": "2022-10-12 05:24:36"
    }
  ]
}
[myuser@myhost ~]$

こちらはidを指定してレシピを閲覧するリクエストとその結果です。
指定したレシピのみが出力されれば成功です。

[myuser@myhost ~]$ curl -X GET https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/my-recipe-prod/recipes/1 | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   314  100   314    0     0    758      0 --:--:-- --:--:-- --:--:--   758
{
  "message": "Recipe details by id",
  "recipe": [
    {
      "id": 1,
      "title": "カレー",
      "making_time": "40分",
      "serves": "4人",
      "ingredients": "肉,玉ねぎ,人参,スパイス,水",
      "cost": 1000,
      "created_at": "2022-10-12 05:00:21",
      "updated_at": "2022-10-12 05:00:21"
    }
  ]
}
[myuser@myhost ~]$

どちらも想定通りに動くことが確認できました!

④続いて、レシピを更新してみます。
最初に登録したレシピのタイトルを「カレー」から「最強カレー」にしてみます。

[myuser@myhost ~]$ curl -X PATCH -H "Content-Type: application/json" -d '{"title":"最強カレー"}'  https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/my-recipe-prod/recipes/1 | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   413  100   386  100    27   1047     73 --:--:-- --:--:-- --:--:--  1119
{
  "message": "Recipe successfully updated!",
  "recipe": [
    {
      "id": 1,
      "title": "最強カレー",
      "making_time": "40分",
      "serves": "4人",
      "ingredients": "肉,玉ねぎ,人参,スパイス,水",
      "cost": 1000,
      "created_at": "2022-10-12 05:00:21",
      "updated_at": "2022-10-12 06:14:48"
    }
  ]
}
[myuser@myhost ~]$

タイトルと更新日時の値が変わっていることが確認できました。

⑤最後に、レシピを削除してみます。 先ほど更新したカレーのレシピのidを指定してリクエストを投げます。

[myuser@myhost ~]$ curl -X DELETE https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/my-recipe-prod/recipes/1 | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    43  100    43    0     0    103      0 --:--:-- --:--:-- --:--:--   103
{
  "message": "Recipe successfully removed!"
}
[myuser@myhost ~]$

削除が成功したことを示すメッセージが出力されました!

再び全レシピを閲覧するリクエストを投げてみると・・・

[myuser@myhost ~]$ curl -X GET https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/my-recipe-prod/recipes/ | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   529  100   529    0     0   1426      0 --:--:-- --:--:-- --:--:--  1429
{
  "recipes": [
    {
      "id": 2,
      "title": "スープ",
      "making_time": "15分",
      "serves": "2人",
      "ingredients": "トマト,ツナ,コンソメ,水",
      "cost": 300,
      "created_at": "2022-10-12 05:22:57",
      "updated_at": "2022-10-12 05:22:57"
    },
    {
      "id": 3,
      "title": "だし巻き卵",
      "making_time": "5分",
      "serves": "2人",
      "ingredients": "卵,だし,水",
      "cost": 150,
      "created_at": "2022-10-12 05:24:36",
      "updated_at": "2022-10-12 05:24:36"
    }
  ]
}
[myuser@myhost ~]$

カレーのレシピが削除されていることが確認できました!

おわりに

今回はAWS上でRESTful APIを作ってみました。

作業前は3時間くらいで作れるかな~と思っていたのですが、実際には8時間くらいかかってしまいました。
この差分5時間のほとんどは、API Gateway - Lambda間のデータのやり取りを実装するのに費やしました。

API Gateway - Lambdaのやり取りでなんでそんなに苦労したの?という話は次回の記事で書きたいと思いますので、ぜひお楽しみに!

ここまで読んでいただきありがとうございました^^