def update_item(user_id, item): """ Update an item in the database, adding the quantity of the passed in item to the quantity of any products already existing in the cart. """ table.update_item( Key={"pk": f"user#{user_id}", "sk": item["sk"]}, ExpressionAttributeNames={ "#quantity": "quantity", "#expirationTime": "expirationTime", "#productDetail": "productDetail", }, ExpressionAttributeValues={ ":val": item["quantity"], ":ttl": generate_ttl(days=30), ":productDetail": item["productDetail"], }, UpdateExpression="ADD #quantity :val SET #expirationTime = :ttl, #productDetail = :productDetail", )
def lambda_handler(event, context): """ Idempotent update quantity of products in a cart. Quantity provided will overwrite existing quantity for a specific product in cart, rather than adding to it. """ try: request_payload = json.loads(event["body"]) except KeyError: return { "statusCode": 400, "headers": get_headers(), "body": json.dumps({"message": "No Request payload"}), } # retrieve the product_id that was specified in the url product_id = event["pathParameters"]["product_id"] quantity = int(request_payload["quantity"]) cart_id, _ = get_cart_id(event["headers"]) # Because this method can be called anonymously, we need to check if there's a logged in user user_sub = None jwt_token = event["headers"].get("Authorization") if jwt_token: user_sub = get_user_sub(jwt_token) try: product = get_product_from_external_service(product_id) except NotFoundException: logger.info("No product found with product_id: %s", product_id) return { "statusCode": 404, "headers": get_headers(cart_id=cart_id), "body": json.dumps({"message": "product not found"}), } # Prevent storing negative quantities of things if quantity < 0: return { "statusCode": 400, "headers": get_headers(cart_id), "body": json.dumps( { "productId": product_id, "message": "Quantity must not be lower than 0", } ), } # Use logged in user's identifier if it exists, otherwise use the anonymous identifier if user_sub: pk = f"user#{user_sub}" ttl = generate_ttl( 7 ) # Set a longer ttl for logged in users - we want to keep their cart for longer. else: pk = f"cart#{cart_id}" ttl = generate_ttl() table.put_item( Item={ "pk": pk, "sk": f"product#{product_id}", "quantity": quantity, "expirationTime": ttl, "productDetail": product, } ) logger.info("about to add metrics...") metrics.add_metric(name="CartUpdated", unit="Count", value=1) return { "statusCode": 200, "headers": get_headers(cart_id), "body": json.dumps( {"productId": product_id, "quantity": quantity, "message": "cart updated"} ), }
def lambda_handler(event, context): """ Add a the provided quantity of a product to a cart. Where an item already exists in the cart, the quantities will be summed. """ logger.debug(event) try: request_payload = json.loads(event["body"]) except KeyError: return { "statusCode": 400, "headers": get_headers(), "body": json.dumps({"message": "No Request payload"}), } product_id = request_payload["productId"] quantity = request_payload.get("quantity", 1) cart_id, _ = get_cart_id(event["headers"]) # Because this method can be called anonymously, we need to check there's a logged in user user_sub = None jwt_token = event["headers"].get("Authorization") if jwt_token: user_sub = get_user_sub(jwt_token) try: product = get_product_from_external_service(product_id) except NotFoundException: return { "statusCode": 404, "headers": get_headers(cart_id=cart_id), "body": json.dumps({"message": "product not found"}), } if user_sub: pk = f"user#{user_sub}" ttl = generate_ttl( 7 ) # Set a longer ttl for logged in users - we want to keep their cart for longer. else: pk = f"cart#{cart_id}" ttl = generate_ttl() if int(quantity) < 0: table.update_item( Key={ "pk": pk, "sk": f"product#{product_id}" }, ExpressionAttributeNames={ "#quantity": "quantity", "#expirationTime": "expirationTime", "#productDetail": "productDetail", }, ExpressionAttributeValues={ ":val": quantity, ":ttl": ttl, ":productDetail": product, ":limit": abs(quantity), }, UpdateExpression= "ADD #quantity :val SET #expirationTime = :ttl, #productDetail = :productDetail", # Prevent quantity less than 0 ConditionExpression="quantity >= :limit", ) else: table.update_item( Key={ "pk": pk, "sk": f"product#{product_id}" }, ExpressionAttributeNames={ "#quantity": "quantity", "#expirationTime": "expirationTime", "#productDetail": "productDetail", }, ExpressionAttributeValues={ ":val": quantity, ":ttl": generate_ttl(), ":productDetail": product, }, UpdateExpression= "ADD #quantity :val SET #expirationTime = :ttl, #productDetail = :productDetail", ) return { "statusCode": 200, "headers": get_headers(cart_id), "body": json.dumps({ "productId": product_id, "message": "product added to cart" }), }
def test_lambda_handler(self): """ API Handler tester The API catch the request and builds a record in dynamodb for each request with sender's IP, build and id and timestamp """ # Controls body try: request_payload = json.loads(self.event["body"]) except KeyError or ValueError: return { "statusCode": 400, "body": json.dumps({"message": "No Request payload"}), } # Controls payload : clientId is mandatory` client_id = "" try: client_id = request_payload["client_id"] except KeyError: return { "statusCode": 400, "headers": get_headers(client_id), "body": json.dumps({"message": "No client_id in payload ?"}), } # Build the record ip = requests.get("http://checkip.amazonaws.com/").text.replace("\n", "") pk = str(uuid.uuid4()) timestamp = time.strftime('%Y-%m-%d %H:%M:%S') ttl = str(generate_ttl(7)) result = self.dynamodb.update_item( TableName=self.tableName, Key={ "pk": {"S": pk}, "sk": {"S": f"ip#{ip}"} }, ExpressionAttributeNames={ "#ip": "ip", "#ttl": "ttl", "#client_id": "client_id", "#timestamp": "timestamp" }, ExpressionAttributeValues={ ":ip": {"S": ip}, ":ttl": {"N": ttl}, ":client_id": {"S": client_id}, ":timestamp": {"S": timestamp} }, UpdateExpression="SET #ttl=:ttl, #client_id=:client_id, #timestamp=:timestamp", ReturnValues="ALL_NEW" ) pprint(result) # metrics.add_metric(name="GreetingAdded", unit="Count", value=1) response = { "statusCode": 200, "headers": get_headers(pk), "body": json.dumps( {"client_id": client_id, "ip": ip, "message": "Greetings added !"} ), } pprint(response) self.assertEqual(response['statusCode'], 200)