I have written the below code and have deployed in AWS Lambda using deployment package :
from flask import Flask,jsonify,request
app = Flask(__name__)
books = [
{'id': 0,
'title': 'A Fire Upon the Deep',
'author': 'Vernor Vinge',
'first_sentence': 'The coldsleep itself was dreamless.',
'year_published': '1992'},
{'id': 1,
'title': 'The Ones Who Walk Away From Omelas',
'author': 'Ursula K. Le Guin',
'first_sentence': 'With a clamor of bells that set the swallows soaring, the Festival of Summer came to the city Omelas, bright-towered by the sea.',
'published': '1973'},
{'id': 2,
'title': 'Dhalgren',
'author': 'Samuel R. Delany',
'first_sentence': 'to wound the autumnal city.',
'published': '1975'}
]
#app.route("/listbooks",methods=['GET'])
def hello():
return jsonify(books)
#app.route("/getbookbyid",methods=['GET'])
def getBybookid(event,context):
if 'id' in request.args:
id=int(request.args['id'])
results=[]
for book in books:
if book['id']==id:
results.append(book)
return jsonify(results)
I have configured API Gateway to hit the lambda function for a GET request.
When i am trying to hit the endpoint using postman I am getting :
Working outside of request context error
Any pointers
The error message "Working outside of request context" is a Flask error, not an API Gateway or Lambda error. It happens when your Flask app tries to access request, or anything that uses it, outside of a request context.
As #BSQL suggests, this seems to be because of the incorrect indentation of your code.
Please add the below line. It will solve your error.
app.app_context().push()
-Prasanna.K
Related
I am trying to develop a to do notes app in django framework. And I want to integrate Google Calendar Api with this project to sync tasks with google calendar. I followed the steps from this website: https://blog.benhammond.tech/connecting-google-cal-api-and-django#comments-list
But when I try to test the demo page of website, it shows Service Error 503. Please let me kindly know how to fix the problem! I only know some basics of django.
Here's my calendar API Code-
from decouple import config
from google.oauth2 import service_account
import googleapiclient.discovery
import datetime
import json
CAL_ID = "104a92a3cd198c2062645e570737318d05c2dfb2f1361e64b743a4b0e223de66#group.calendar.google.com"
SCOPES = ['https://www.googleapis.com/auth/calendar']
SERVICE_ACCOUNT_FILE = json.load(open('google-credentials.json'))
def test_calendar():
print("RUNNING TEST_CALENDAR()")
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
service = googleapiclient.discovery.build(
'calendar', 'v3', credentials=credentials)
print(service)
# CREATE A NEW EVENT
new_event = {
'summary': "New Task 1",
'location': 'Kolkata, WB',
'description': 'Description of Task 1',
'start': {
'date': f"{datetime.date.today()}",
'timeZone': 'America/New_York',
},
'end': {
'date': f"{datetime.date.today() + datetime.timedelta(days=3)}",
'timeZone': 'America/New_York',
},
}
service.events().insert(calendarId=CAL_ID, body=new_event).execute()
print('Event created')
# GET ALL EXISTING EVENTS
events_result = service.events().list(
calendarId=CAL_ID, maxResults=2500).execute()
events = events_result.get('items', [])
# LOG THEM ALL OUT IN DEV TOOLS CONSOLE
for e in events:
print(e)
# uncomment the following lines to delete each existing item in the calendar
#event_id = e['id']
# service.events().delete(calendarId=CAL_ID, eventId=event_id).execute()
return events
The interpreter when it runs the test_calendar() function , it doesn't prints the services.
This should let me see the demo page of django where list task are shown taken from the google calender.
I have a API Gateway service based on FastAPI and some specific services (like plugins) to connect with it. One of them - Auth service dealing with user accounts and access-tokens.
For example Auth service wants to tell AG about new functionality he provides and to register new endpoint in AG at runtime.
I see the following steps:
Auth creates new endpoint in AG, /new_endpoint for example;
All the traffic going to http://AG/new_endpoint will be redirected to http://Auth/...
I looked at the method FastAPI.add_api_route to add new endpoint. It works at runtime - I checked using curl.
There is no effect after refreshing http://AG/docs page because OpenAPI schema is cached.
I would like to re-generate OpenAPI schema and see /new_endpoint on the OpenAPI page.
I think I found the solution how to re-generate OpenAPI schema.
Drop cache app.openapi_schema = None
Re-generate schema app.setup()
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel
app = FastAPI()
class NewEndpointResponse(BaseModel):
status: str
method: str
url_path: str
async def catch_all(request: Request) -> JSONResponse:
"""
Your new endpoint handler
"""
# some logic to interact with Auth-service
# like: requests.get("http://Auth/...")
res = NewEndpointResponse(status="OK", method=request.method, url_path=request.url.path)
return JSONResponse(res.dict(), status_code=200)
class EndpointRegisterDTO(BaseModel):
endpoint: str = "/new_endpoint"
method: str = "GET"
name: str = "Extra Functionality"
#app.post("/register/endpoint")
async def add_endpoint(request: EndpointRegisterDTO):
"""
Adds new endpoint at runtime
"""
app.add_api_route(
request.endpoint,
catch_all,
methods=[request.method],
name=request.name,
response_model=NewEndpointResponse)
app.openapi_schema = None
app.setup()
return {"status": "OK"}
Open http://AG/docs. Only one endpoint is available.
Press "Try it out" and do POST /register/endpoint with suggested parameters.
Refresh http://AG/docs - now you can see /new_endpoint.
Call GET /new_endpoint and check that response is correct.
The solution is ugly a bit, but it works!
I think it's bloody hard to debug it!
The code in the documentation is:
A very simple ASGI app that simply returns a response containing hello is, (file hello_world.py)
async def app(scope, receive, send):
if scope["type"] != "http":
raise Exception("Only the HTTP protocol is supported")
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
(b'content-type', b'text/plain'),
(b'content-length', b'5'),
],
})
await send({
'type': 'http.response.body',
'body': b'hello',
})
simply run via
hypercorn hello_world:app
But the problem is, i do not want to handle type, status or headers.
I can do it with fastapi. Here, i do not need to handle type, status or headers. Given the file name is hello_world.py
from fastapi import FastAPIapp = FastAPI()
#app.get("/")
async def root():
return {"message": "Hello world!"}
simply run using
hypercorn hello_world:app
How can I have this fastapi like behaviour without fastapi. I mean is there any simple http parser which i can use instead of fastapi. Custom code would be even better.
I have a basic lambda function which accepts a JSON, and transforms to XML and uploads the same to s3 bucket. I am running the test through the lambda console and the xml is getting generated and uploaded to s3 as well. Issue happens when I run the test through API Gateway, and there I get the error:
"message": "Internal server error" and Status: 502. The error also points out where is the code issue:
{"errorMessage": "'header'", "errorType": "KeyError", "stackTrace": [" File \"/var/task/sample.py\", line 21, in printMessage\n b1.text = event['header']['echoToken']\n"]}
The same code is working when running through lambda console. Below is the code snippet with the line that throws the error:
def printMessage(event, context):
print(event)
#event = json.loads(event['header'])
root = ET.Element("Reservation")
m1 = ET.Element("header")
root.append(m1)
b1 = ET.SubElement(m1, "echoToken")
b1.text = event['header']['echoToken'] #this line throws error
I got a similar question here:
AWS Lambda-API gateway "message": "Internal server error" (502 Bad Gateway). Below is the print of event object.
{'header': {'echoToken': '907f44fc-6b51-4237-8018-8a840fd87f04', 'timestamp': '2018-03-07 20:59:575Z'}, 'reservation': {'hotel': {'uuid': '3_c5f3c903-c43d-4967-88d1-79ae81d00fcb', 'code': 'TASK1', 'offset': '+06:00'}, 'reservationId': 12345, 'confirmationNumbers': [{'confirmationNumber': '12345', 'source': 'ENCORA', 'guest': 'Arturo Vargas'}, {'confirmationNumber': '67890', 'source': 'NEARSOFT', 'guest': 'Carlos Hernández'}], 'lastUpdateTimestamp': '2018-03-07 20:59:541Z', 'lastUpdateOperatorId': 'task.user'}}
As per the solution in the link, if I try to do : header = json.loads(event['header'])
I get the below error:
"errorMessage": "the JSON object must be str, bytes or bytearray, not dict",
This is a task that I need to complete, and I have tried few things, but is always failing when tested through API Gateway and POSTMAN. So, my question is: I don't want to change my complete code for XML transformation, and is there any way that I load the complete event object in python, so that it works both through lambda console and API gateway?
Thanks in Advance!!
The problem is similar to the one discussed here
Below code will fix the line causing the issue.
eventDict = json.loads(event)
b1Text = json.dumps(eventDict['header']['echoToken'])
print(b1Text)
I have a flask app deployed to Heroku and would like to receive text from Chatfuel (bot building platform) and send back texts in return.
Now, what I did is to use my heroku app as a web-hook, so that Chatfuel can make a simple GET or POST query to my API. The problem is that I have no experience with Flask or APIs, so I am not sure about how my app can receive information (in json format) and send it back to chatfuel.
This is what I wrote so far:
import os
import sys
import json
import requests
from flask import Flask, jsonify, render_template, request
app = Flask(__name__)
#app.route('/', methods=['GET'])
def verify():
# when the endpoint is registered as a webhook, it must echo back
# the 'hub.challenge' value it receives in the query arguments
if request.args.get("hub.mode") == "subscribe" and request.args.get("hub.challenge"):
if not request.args.get("hub.verify_token") == os.environ["VERIFY_TOKEN"]:
return "Verification token mismatch", 403
return request.args["hub.challenge"], 200
return "Hello world", 200
#app.route("/json", methods=['GET','POST'])
def json():
url = "chatfuel_api"
data = json.load(urllib2.urlopen(url))
if request.json:
mydata = request.json
return "Thanks",200
else:
return "no json received"
#app.route('/hello', methods = ['GET','POST'])
def api_echo():
if request.method == 'GET':
return "ECHO: GET\n",200
if __name__ == '__main__':
app.run(debug=True)
The verify() function works, as I see an 'Hello world' message if I run the app locally. However, both json() and api_echo() don't work, and when my server receives a get or post request from chatfuel, it returns a 404 error.
As you can see, I really have a lot of confusion, and your help would be really invaluable.
Thanks
You need to make sure you have registered the proper webhook url with Chatfuel. For the code you currently have, to hit the json endpoint the url would be https://www.your_server.com/json
The verify route looks like the hub challenge FB sends, so you would have to register the root of your site (that is, with your current code) with FB to hit the verify function. That url would look like this https://www.your_site.com/