restful api を chalice で紐解く 〜 python serverless microframework for aws 〜
TRANSCRIPT
•
••
•
••••••
see@http://www.restapitutorial.com/lessons/whatisrest.html
������
����
RESTAPI
Client
Mobile client
RESTAPI
GET /users HTTP/1.1
{"users": […]}
RESTAPI
AmazonDynamoDB
AmazonS3
AmazonCloudWatch
Auto Scaling group
Security group
Elastic Load Balancing
Instance
REST API
AmazonDynamoDB
AmazonCloudWatch
AmazonS3
AmazonDynamoDB
AmazonCloudWatch
Amazon API Gateway
AWS Lambda
AmazonS3
Lambda.GetFunction(params: {'body': '', 'url': u'https://lambda.us-west-2.amazonaws.com/2015-03-31/functionIAM.GetRole(params: {'body': {'Action': u'GetRole', 'RoleName': u'helloworld7', 'Version': u'2010-05IAM.CreateRole(params: {'body': {'Action': u'CreateRole', 'RoleName': u'helloworld7', 'Version': u'2010IAM.PutRolePolicy(params: {'body': {'Action': u'PutRolePolicy', 'RoleName': u'helloworld7', 'PolicyDocumentLambda.CreateFunction(params: (... omitted from logs due to size ...)APIGateway.GetRestApis(params: {'body': '', 'url': u'https://apigateway.us-west-2.amazonaws.com/restapisAPIGateway.CreateRestApi(params: {'body': '{"name": "helloworld7"}', 'url': u'https://apigateway.usAPIGateway.GetResources(params: {'body': '', 'url': u'https://apigateway.us-west-2.amazonaws.com/restapisAPIGateway.PutMethod(params: {'body': '{"authorizationType": "NONE"}', 'url': u'https://apigateway.usAPIGateway.PutIntegration(params: {'body': '{"httpMethod": "POST", "requestTemplates": {"application/APIGateway.PutMethodResponse(params: {'body': '{"responseModels": {"application/json": "Empty"}}', 'APIGateway.PutIntegrationResponse(params: {'body': '{"responseTemplates": {"application/json": ""}}', 'APIGateway.PutMethodResponse(params: {'body': '{"responseModels": {"application/json": "Empty"}}', 'APIGateway.PutIntegrationResponse(params: {'body': '{"selectionPattern": "ChaliceViewError.*", "responseTemAPIGateway.PutMethodResponse(params: {'body': '{"responseModels": {"application/json": "Empty"}}', 'APIGateway.PutIntegrationResponse(params: {'body': '{"selectionPattern": "BadRequestError.*", "responseTempAPIGateway.PutMethodResponse(params: {'body': '{"responseModels": {"application/json": "Empty"}}', 'APIGateway.PutIntegrationResponse(params: {'body': '{"selectionPattern": "NotFoundError.*", "responseTemplaAPIGateway.PutMethodResponse(params: {'body': '{"responseModels": {"application/json": "Empty"}}', 'APIGateway.PutIntegrationResponse(params: {'body': '{"selectionPattern": "UnauthorizedError.*", "responseTeAPIGateway.PutMethodResponse(params: {'body': '{"responseModels": {"application/json": "Empty"}}', 'APIGateway.PutIntegrationResponse(params: {'body': '{"selectionPattern": "ForbiddenError.*", "responseTemplAPIGateway.PutMethodResponse(params: {'body': '{"responseModels": {"application/json": "Empty"}}', 'APIGateway.PutIntegrationResponse(params: {'body': '{"selectionPattern": "ConflictError.*", "responseTemplaAPIGateway.PutMethodResponse(params: {'body': '{"responseModels": {"application/json": "Empty"}}', 'APIGateway.PutIntegrationResponse(params: {'body': '{"selectionPattern": "TooManyRequestsError.*", "Lambda.GetPolicy(params: {'body': '', 'url': u'https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/Lambda.AddPermission(params: {'body': '{"Action": "lambda:InvokeFunction", "StatementId": "1e964686APIGatewayCreateDeployment(params: {'body': '{"stageName": "dev"}', 'url': u'https://apigateway.us-
�� #��� API ����!"�� ���������# AWS SAM ����������
https://github.com/aws/chalice
•
••
••
••
$ pip install chalice$ chalice new-project helloworld && cd helloworld$ cat app.py
from chalice import Chalice
app = Chalice(app_name="helloworld")
@app.route("/")def index():
return {"hello": "world"}
$ chalice deploy...https://endpoint/api
$ curl https://endpoint/api{"hello": "world"}
$ git difffrom chalice import Chalice+import boto3
app = Chalice(app_name='chalice-sample')+S3 = boto3.client('s3', region_name='us-east-1')
@app.route('/')def index():
+ S3.get_object(Bucket = BUCKET, Key = key)return {'hello': 'world'}
$ chalice deployCreating role: chalice-sample-devThe following execution policy will be used:{"Version": "2012-10-17","Statement": [{ "Effect": "Allow","Action": ["s3:GetObject"
],"Resource": ["*"],"Sid": "40e10c45a..."
},...
}Would you like to continue? [Y/n]:
$ chalice localServing on localhost:8000
$ npm install -g nodemon$ nodemon --exec "chalice local" --watch *.py[nodemon] 1.12.5[nodemon] to restart at any time, enter `rs`[nodemon] watching: app.py[nodemon] starting `chalice local`Serving on localhost:8000
see@https://qiita.com/TakenoriHirao/items/69f2af5aaf64db77124b
•
•
•
# Basic [email protected]('/')def index():
return {"GET": "/"}
# Specify [email protected]('/', methods=['PUT'])def index_put():
return {"PUT": "/"}
@app.route('/res', methods=['GET', 'POST'])def my_resource():
request = app.current_requestif request.method == 'GET':
return {"GET": "/res"}elif request.method == 'POST':
return {"POST": "/res"}
# Path [email protected]('/myresources/{object_name}')def my_resource_key(object_name):
try:response = S3.get_object(
Bucket = BUCKET, Key = object_name)return response['Body'].read()
except ClientError as e:raise e
@app.route('/s3/{bucket_name}/objects')def objects_of(bucket_name):
try:response =
S3.list_objects_v2(Bucket=bucket_name, Prefix = S3_PREFIX)
objects = list(map(lambda x: x["Key"], response["Contents"]))
return {"objects": objects}except ClientError as e:
raise ...
@app.route('/')def index():
return Response(body = 'hello world!',status_code = 200,headers = {'Content-Type': 'text/plain'}
)
@app.route('/',cors=True,api_key_required=True,authorizer=IAMAuthorizer())
def index():return "yey"
@app.schedule(Rate(1,unit=Rate.HOURS))def every_hour(event):
print(event.to_dict())
•••••
class Chalice(object):def route(self, path, **kwargs): # ��������
def _register_view(view_func):self._add_route(path, view_func, **kwargs)return view_func
return _register_view
def _add_route(self, path, view_func, **kwargs):methods = kwargs.pop('methods', ['GET'])...for method in methods:
...entry = RouteEntry(view_func, name,
path, method, api_key_required, content_types, cors, authorizer)
self.routes[path][method] = entry
class Chalice(object):def __call__(self, event, context): # ��������
resource_path = event.get('requestContext', {}).get('resourcePath')
http_method = event['requestContext']['httpMethod']route_entry = self.routes[resource_path][http_method]view_function = route_entry.view_functionfunction_args = {name: event['pathParameters'][name]
for name in route_entry.view_args}...response = self._get_view_function_response(view_function,
function_args)response_headers = CaseInsensitiveMapping(response.headers)...response = response.to_dict(self.api.binary_types)return response
class Chalice(object):def _get_view_function_response(self, view_function, function_args):
try:response = view_function(**function_args)if not isinstance(response, Response):
response = Response(body=response)self._validate_response(response)
except ChaliceViewError as e:response = Response(...)
except Exception as e:headers = {}if self.debug:
...else:
response = Response(..., status_code=500)return response
https://speakerdeck.com/akitsukada/sabaresudewang-dao-webhuremuwakuwoshi-ufang-fa
https://www.slideshare.net/shimy_net/aws-79149218
https://www.slideshare.net/shimy_net/cloud-roadshow-2017-osaka
•••
https://github.com/kislyuk/domovoi
@app.sns_topic_subscriber("bartender")def tend(event, context):
message = json.loads(event["Records"][0]["Sns"]["Message"])context.log(dict(beer="Quadrupel", quantity=message["beer"]))
@app.cloudwatch_event_handler(source=["aws.ecs"])def monitor_ecs_events(event, context):
message = json.loads(event["Records"][0]["Sns"]["Message"])context.log("Got an event from ECS: {}".format(message))
@app.s3_event_handler(bucket="myS3bucket",events=["s3:ObjectCreated:*"], prefix="foo", suffix=".bar")
def monitor_s3(event, context):message = json.loads(event["Records"][0]["Sns"]["Message"])context.log("Got an event from S3: {}".format(message))
••
•
••
••