diff --git a/README.md b/README.md index 37c2f9da8..4a18738a2 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,7 @@ serverless install -u https://github.com/serverless/examples/tree/master/folder- | [Aws Python Pynamodb S3 Sigurl](https://github.com/serverless/examples/tree/master/aws-python-pynamodb-s3-sigurl)
Serverless signed uploader REST API using pynamodb, s3 generated events, custom log format, and DRY serverless.yml with custom section | python | | [Aws Rest With Dynamodb](https://github.com/serverless/examples/tree/master/aws-python-rest-api-with-dynamodb)
Serverless CRUD service exposing a REST HTTP interface | python | | [Aws Rest With Faunadb](https://github.com/serverless/examples/tree/master/aws-python-rest-api-with-faunadb)
Serverless CRUD service exposing a REST HTTP interface | python | +| [Aws Python Rest Api With Pymongo](https://github.com/serverless/examples/tree/master/aws-python-rest-api-with-pymongo)
Serverless pymongo example | python | | [Aws Rest With Pynamodb](https://github.com/serverless/examples/tree/master/aws-python-rest-api-with-pynamodb)
Serverless CRUD service exposing a REST HTTP interface | python | | [Aws Scheduled Cron](https://github.com/serverless/examples/tree/master/aws-python-scheduled-cron)
Example of creating a function that runs as a cron job using the serverless `schedule` event | python | | [Aws Simple Http Endpoint](https://github.com/serverless/examples/tree/master/aws-python-simple-http-endpoint)
Example demonstrates how to setup a simple HTTP GET endpoint with python | python | diff --git a/aws-python-rest-api-with-pymongo/README.md b/aws-python-rest-api-with-pymongo/README.md new file mode 100644 index 000000000..cd5eedf63 --- /dev/null +++ b/aws-python-rest-api-with-pymongo/README.md @@ -0,0 +1,174 @@ + +# aws-python-rest-api-with-dynamodb + +## Create the Mongo Atlas backend + +1. Follow `Part 1: Cluster Creation` of [this artice](https://medium.com/swlh/creating-a-mongodb-cluster-and-inserting-a-document-with-python-ac90cc9d979c) to create a cluster on Mongo Atlas' Free Tier. + +## Deploy the Serverless API to AWS + +1. Install Serverless + + ``` + npm install -g serverless + ``` + +2. Install `serverless-python-requirements` + + ``` + npm i --save serverless-python-requirements + ``` + +3. Define necessary environment variables + + Append this to your ~/.bash_profile + + ``` + export MONGO_DB_USER= + export MONGO_DB_PASS= + export MONGO_DB_NAME=SampleDatabase + export MONGO_COLLECTION_NAME=SampleCollection + export MONGO_DB_URL= + ``` + +4. Deploy the API + + ``` + sls deploy + ``` + + Your results should look something like this: + ``` + Serverless: Stack update finished... + Service Information + service: serverless-pymongo-item-api + stage: dev + region: us-east-1 + stack: serverless-pymongo-item-api-dev + resources: 28 + api keys: + None + endpoints: + POST - https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item + GET - https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item + GET - https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item/{id} + DELETE - https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item/{id} + functions: + create: serverless-pymongo-item-api-dev-create + list: serverless-pymongo-item-api-dev-list + get: serverless-pymongo-item-api-dev-get + delete: serverless-pymongo-item-api-dev-delete + layers: + None + Serverless: Removing old service artifacts from S3... + Serverless: Run the "serverless" command to setup monitoring, troubleshooting and testing. + ``` + +## Test the API by Creating and Querying items + +Substitute your endpoints into these curl commands to test the Create, Read, and Delete operations + +### CREATE + +``` +curl --request POST \ + --url https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item \ + --header 'content-type: application/json' \ + --data '{ + "attribute_1": "Pet", + "attribute_2": "Rock" +}' +``` + +#### Expected Response + +204 status + +``` +{ + "_id": "c6f03ca0-f792-11e9-9534-260a4b91bfe9", + "data": { + "attribute_1": "Pet", + "attribute_2": "Rock" + } +} +``` + +### GET + +``` +curl --request GET \ + --url https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item/c6f03ca0-f792-11e9-9534-260a4b91bfe9 \ + --header 'content-type: application/json' +``` + +#### Expected Response + +200 status + +``` +{ + "_id": "c6f03ca0-f792-11e9-9534-260a4b91bfe9", + "data": { + "attribute_1": "Pet", + "attribute_2": "Rock" + } +} +``` + +### LIST + +``` +curl --request GET \ + --url https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item \ + --header 'content-type: application/json' +``` + +### Expected Response + +200 status + +``` +{ + "response_items": [ + { + "_id": "c6f03ca0-f792-11e9-9534-260a4b91bfe9", + "data": { + "attribute_1": "Pet", + "attribute_2": "Rock" + } + }, + { + "_id": "717c5f36-f799-11e9-a921-1e0e685be73c", + "data": { + "attribute_1": "Pete", + "attribute_2": "Rock" + } + } + ], + "filter": null +} +``` + +## Delete + +``` +curl --request DELETE \ + --url https://0xfyi15qci.execute-api.us-east-1.amazonaws.com/dev/item/c6f03ca0-f792-11e9-9534-260a4b91bfe9 \ + --header 'content-type: application/json' +``` + +### Expected Response + +204 status + diff --git a/aws-python-rest-api-with-pymongo/item/__init__.py b/aws-python-rest-api-with-pymongo/item/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/aws-python-rest-api-with-pymongo/item/create.py b/aws-python-rest-api-with-pymongo/item/create.py new file mode 100644 index 000000000..946f38cb6 --- /dev/null +++ b/aws-python-rest-api-with-pymongo/item/create.py @@ -0,0 +1,39 @@ +import json +import os +import uuid +import pymongo + +# Fetch mongo env vars +usr = os.environ['MONGO_DB_USER'] +pwd = os.environ['MONGO_DB_PASS'] +mongo_db_name = os.environ['MONGO_DB_NAME'] +mongo_collection_name = os.environ['MONGO_COLLECTION_NAME'] +url = os.environ['MONGO_DB_URL'] + +# Connection String +client = pymongo.MongoClient("mongodb+srv://" + usr + ":" + pwd + "@" + url + "/test?retryWrites=true&w=majority") +db = client[mongo_db_name] +collection = db[mongo_collection_name] + + +def create(event, context): + # get request body + data = json.loads(event['body']) + + # create item to insert + item = { + '_id': str(uuid.uuid1()), + 'data': data, + } + + # write item to database + collection.insert_one(item) + + # create response + response = { + "statusCode": 200, + "body": json.dumps(item) + } + + # return response + return response diff --git a/aws-python-rest-api-with-pymongo/item/delete.py b/aws-python-rest-api-with-pymongo/item/delete.py new file mode 100644 index 000000000..74a74f507 --- /dev/null +++ b/aws-python-rest-api-with-pymongo/item/delete.py @@ -0,0 +1,38 @@ +import os +import pymongo + +# Fetch mongo env vars +usr = os.environ['MONGO_DB_USER'] +pwd = os.environ['MONGO_DB_PASS'] +mongo_db_name = os.environ['MONGO_DB_NAME'] +mongo_collection_name = os.environ['MONGO_COLLECTION_NAME'] +url = os.environ['MONGO_DB_URL'] + +# Connection String +client = pymongo.MongoClient("mongodb+srv://" + usr + ":" + pwd + "@" + url + "/test?retryWrites=true&w=majority") +db = client[mongo_db_name] +collection = db[mongo_collection_name] + + +def delete(event, context): + # get item_id to delete from path parameter + item_id = event['pathParameters']['id'] + + # delete item from the database + del_resp = collection.delete_one({"_id": item_id}) + + # if no item return 404 + if del_resp.deleted_count == 0: + + response = { + "statusCode": 404, + } + + return response + + # create a response + response = { + "statusCode": 204, + } + + return response diff --git a/aws-python-rest-api-with-pymongo/item/get.py b/aws-python-rest-api-with-pymongo/item/get.py new file mode 100644 index 000000000..9bab17bcd --- /dev/null +++ b/aws-python-rest-api-with-pymongo/item/get.py @@ -0,0 +1,32 @@ +import json +import os +import pymongo + +# Fetch mongo env vars +usr = os.environ['MONGO_DB_USER'] +pwd = os.environ['MONGO_DB_PASS'] +mongo_db_name = os.environ['MONGO_DB_NAME'] +mongo_collection_name = os.environ['MONGO_COLLECTION_NAME'] +url = os.environ['MONGO_DB_URL'] + +# Connection String +client = pymongo.MongoClient("mongodb+srv://" + usr + ":" + pwd + "@" + url + "/test?retryWrites=true&w=majority") +db = client[mongo_db_name] +collection = db[mongo_collection_name] + + +def get(event, context): + # get item_id to delete from path parameter + item_id = event['pathParameters']['id'] + + # delete item from the database + item = collection.find_one({"_id": item_id}) + + # create a response + response = { + "statusCode": 200, + "body": json.dumps(item) + } + + # return response + return response diff --git a/aws-python-rest-api-with-pymongo/item/list.py b/aws-python-rest-api-with-pymongo/item/list.py new file mode 100644 index 000000000..8e71f2915 --- /dev/null +++ b/aws-python-rest-api-with-pymongo/item/list.py @@ -0,0 +1,46 @@ +import json +import os +import pymongo + +# Fetch mongo env vars +usr = os.environ['MONGO_DB_USER'] +pwd = os.environ['MONGO_DB_PASS'] +mongo_db_name = os.environ['MONGO_DB_NAME'] +mongo_collection_name = os.environ['MONGO_COLLECTION_NAME'] +url = os.environ['MONGO_DB_URL'] + +# Connection String +client = pymongo.MongoClient("mongodb+srv://" + usr + ":" + pwd + "@" + url + "/test?retryWrites=true&w=majority") +db = client[mongo_db_name] +collection = db[mongo_collection_name] + + +def list(event, context): + # create response body object + response_body = {} + + # create array for reponse items + response_body['response_items'] = [] + + # return path parameters with filter key + response_body['filter'] = event['multiValueQueryStringParameters'] + + # build query with any path parameters + query = {} + if event['multiValueQueryStringParameters'] is not None: + for parameter in event['multiValueQueryStringParameters']: + query[parameter] = event['multiValueQueryStringParameters'][parameter][0] + + # create list of items + cursor = collection.find(query) + for document in cursor: + response_body['response_items'].append(document) + + # create response + response = { + "statusCode": 200, + "body": json.dumps(response_body) + } + + # return response + return response diff --git a/aws-python-rest-api-with-pymongo/package.json b/aws-python-rest-api-with-pymongo/package.json new file mode 100644 index 000000000..7ce71273d --- /dev/null +++ b/aws-python-rest-api-with-pymongo/package.json @@ -0,0 +1,10 @@ +{ + "name": "aws-python-rest-api-with-pymongo", + "version": "1.0.0", + "description": "Serverless pymongo example", + "author": "", + "license": "MIT", + "dependencies": { + "serverless-python-requirements": "^5.0.0" + } +} diff --git a/aws-python-rest-api-with-pymongo/requirements.txt b/aws-python-rest-api-with-pymongo/requirements.txt new file mode 100644 index 000000000..c830322a6 --- /dev/null +++ b/aws-python-rest-api-with-pymongo/requirements.txt @@ -0,0 +1,2 @@ +pymongo +dnspython diff --git a/aws-python-rest-api-with-pymongo/serverless.yml b/aws-python-rest-api-with-pymongo/serverless.yml new file mode 100644 index 000000000..f7f455c13 --- /dev/null +++ b/aws-python-rest-api-with-pymongo/serverless.yml @@ -0,0 +1,51 @@ +service: serverless-pymongo-item-api + +frameworkVersion: ">=1.1.0 <2.0.0" + +plugins: + - serverless-python-requirements + +provider: + name: aws + runtime: python3.7 + environment: + MONGO_DB_USER: ${env:MONGO_DB_USER} + MONGO_DB_PASS: ${env:MONGO_DB_PASS} + MONGO_DB_NAME: ${env:MONGO_DB_NAME} + MONGO_DB_URL: ${env:MONGO_DB_URL} + MONGO_COLLECTION_NAME: ${env:MONGO_COLLECTION_NAME} + iamManagedPolicies: + - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + +functions: + create: + handler: item/create.create + events: + - http: + path: item + method: post + cors: true + + list: + handler: item/list.list + events: + - http: + path: item + method: get + cors: true + + get: + handler: item/get.get + events: + - http: + path: item/{id} + method: get + cors: true + + delete: + handler: item/delete.delete + events: + - http: + path: item/{id} + method: delete + cors: true