はじめに
AWS環境にゴミ分別をしてくれるAPIを作ります。
Cloud9を使用します。試してみた記事は以下です。
設計
分別したいゴミをパラメータで渡すと結果を返すAPIを作ります。
ごみの分別ですが、川崎市のゴミ分別のデータセットがCCライセンスで公開されているのでそれを使用します。
データセットは更新されることがありそうです。
このことから、APIは以下のようにバージョンも指定できるようにします。
GET /garbage?word=皿&v=300110
開発
lambda関数を作成する
cloud9からAPI Gatewayと連携したLambdaを作成します。
[AWS Resources]からLambdaの追加アイコンを選択。
名前は適当。
テンプレートはAPI Gatewayを使っているものを選んでみました。
エンドポイントのパスも適当に。セキュリティは後々考えます。
開発なのでメモリは最低。Roleは自動生成します。
Finish!
できました。
Lambda関数を実装する
テンプレートとして利用したものはDynamoDBを使用していますが、ここではそこまでする必要はないので、インスタンス単位でCSVファイルを読み込むこととします。
あとは読み込んだファイルの内容からマッピングを返すだけなので、説明することはありません。
注意点はコピーしてきた公開されているCSVファイルがShift-JISである点くらいです。
# -*- coding: utf-8 -*-
import csv
import json
import os
import logging
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG)
_cache = None
class AppError(Exception):
"""
汎用エラークラス
"""
def __init__(self, message):
self.message = message
def lambda_handler(event, _):
"""
lambda
:param event:
:param _: context
:return:
"""
print("Received event: " + str(event))
version = event.get('queryStringParameters', {}).get('v', None)
word = event.get('queryStringParameters', {}).get('word', None)
# 入力チェック
if not version or not word:
return respond(None, err=AppError('invalid parameter'))
# データベースの取得
if not _update_cache(version):
return respond(None, err=AppError('Unsupported version "{}"'.format(version)))
result = _cache.get(version, {}).get(word, '分類できませんでした')
return respond({
'version': version,
'classification': result,
})
def _update_cache(version):
"""
データベースを更新する
:param version:
:return:
"""
global _cache
if not _cache:
_cache = {}
if version not in _cache:
_cache[version] = {}
filename = './' + version + '.csv'
if os.path.exists(filename):
with open(filename, 'r', encoding='shift_jis') as f:
reader = csv.reader(f)
next(reader)
# 0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8
# ID,頭文字,品目名,読み,類似語,出し方(一覧),出し方(詳細),出し方のポイント,URL1
for row in reader:
out = row[5]
if row[6].strip():
out += 'または' + row[6]
_cache[version][row[2]] = out
_cache[version][row[3]] = out
if row[4].strip():
synonyms = row[4].split(' ')
for synonym in synonyms:
_cache[version][synonym] = out
return True
else:
logger.warning('file not exist.')
return False
else:
# すでに取得済み
return True
def respond(res, err=None):
"""
API Response
:param err:
:param res:
:return:
"""
return {
'statusCode': '400' if err else '200',
'body': err.message if err else json.dumps(res, ensure_ascii=False, indent=2),
'headers': {
'Content-Type': 'application/json',
},
}
サーバーレスの設定
デプロイ時の設定はtemplate.yamlで行います。テンプレートで作成済みです。
ここではMemorySizeを小さく、受け取るMethodをGETのみにする、といった変更を行いました。
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: An AWS Serverless Specification template describing your function.
Resources:
garbage:
Type: 'AWS::Serverless::Function'
Properties:
Handler: garbage/lambda_function.lambda_handler
Runtime: python3.6
Description: ''
MemorySize: 128
Timeout: 15
CodeUri: .debug/
Events:
LambdaMicroservice:
Type: Api
Properties:
Path: /garbage
Method: GET
garbagePermission:
Type: 'AWS::Lambda::Permission'
Properties:
Action: 'lambda:InvokeFunction'
FunctionName:
'Fn::GetAtt':
- garbage
- Arn
Principal: apigateway.amazonaws.com
SourceArn:
'Fn::Sub': 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*/*/*'
デプロイ
IDEのLambdaメニューからデプロイします。
確認
AWSのAPI GatewayからURLを確認して実行してみます。
https://****************.us-west-2.amazonaws.com/Stage/garbage?word=パソコンケース&v=300110
ブラウザなどから取得したURLを入力して以下のようなレスポンスが返ってくればOKです。
{
"version": "300110",
"classification": "普通ごみまたは粗大ごみ"
}
おわりに
このAPIを使用した企みは別の記事で行います。
参考
AWS Cloud9 Integrated Development Environment (IDE) で AWS Lambda 関数を操作する - AWS Cloud9
Python3 で CSV の読み書きをする方法 – Shift_JIS と UTF-8 対応サンプルコード付 | Crane & to.