How do I run a script when an api endpoint is hit? - python

Here is how I want my program to work. Step 2 is what I am unsure of how to implement.
Client makes API call to /email endpoint
/email endpoint has a script run that gather emails from GMAIL API
Put contents into response object
Returns response object back to client
I understand how to make a static api response. But I can't get a python script to run when the api endpoint is hit.

I saw the flask tag in your post.
I only played around with flask for certain interviews, but know enough to say calling a python script outside your running server is somewhat of an antipattern.
I assume your backend is a flask app, so ideally, you'd want to wrap whatever script you have in your python script file in a function and simply call it from your flask method when the endpoint is hit.
Something like:
from flask import Flask
from custom_emails_module import gather_email
#api.route('/email', methods=["GET"])
def method_associated_with_your_endpoint():
# additional
gather_email()
where custom_emails_module should be the module you create for your gather_emails script.
Now, at the end of your gather_emails function, simple remember to return the correct type, usually done with:
return json.dumps("success": True, "data": python_object_with_several_emails)
Use something like PostMan for local debugging and remember to use application/json in header for Content-Type.
Good luck!

Related

Properly Unit test around a Flask App and Mocking Flask.request.json? [duplicate]

This question already has an answer here:
Testing code that requires a Flask app or request context
(1 answer)
Closed 3 years ago.
I'm attempting to write unit tests for a file that is included inside of a flask app (microservice to handle some RESTful endpoints). Some things I'm running into: All the documentation and questions I seem to find involve invoking the APIs themselves, this isn't proper I need to invoke the post function directly with a mocked fake request that I've setup as I need to test functionality.
I'm able to attempt to mock the request.json object however i'm always met with "RuntimeError: Working outside of request context".I've attempted to use test_request_context() but that leads to the same issue. Then I started diving deeper into Flask and attempting to us app.test_client() however this has it's own problems alongside of calling the endpoint directly and doesn't let me unit test my function properly, they start moving into the realm of being integration tests.
This is the function i'm attempting to test:
#api.route...
class HandleRoute(Resource):
#authentication #<-- I want to Mock True or False response
def post(self): #<-- I want to call directly
try:
if not request.json #<-- Value I want to mock, from flask.request
How should I be going about this? I'm trying to avoid app.test_client() and other Flask related things as again, the point of these unit tests is to check my code paths as a sanity check, not just what should happen.
You are correct in wanting to actually perform the request, and test the received response. This is the proper way and Flask already has a built-in client to make this easy.
The official documentation already includes an example of how to do this (Testing Flask Applications). If you want to have more control over the request being processed, then have a look at Manually push a context.
I believe you are looking for the following snippet (adapted from this answer):
with app.test_client() as client:
resp = client.post('/route', {'some_key': 'some_data'})
If you want to do away with flask.test_client() you can use python-requests to stay in the python world, or even use javascript based libraries like Chakram or Frisby

How to call rest api in python which is present in other system

Please provide me any example and installation process in python.
Example required is: Python file should available in localhost and server file should available in other system or remote server.So when I run the python file then Api should call for return json from the server file which is present in remote system
Although your question seems a bit unclear but what I infer is that you want a REST API which returns a JSON response after running a business logic on the request params/body.
You might want to have a look at http://www.django-rest-framework.org/ to start with writing a REST API with django-rest-framework.
If you are sure that your server is responding with the data, you can use python requests to send a call to your API and retrieve the data.
import requests
datatosend = {"first_name": "bleh", "last_name": "bleh"}
send = requests.post("http//your_url", data=datatosend)
print(send.content)
If you want a web form to post the data, please do some google search, you would get one.

Flask restful GET doesn't respond within app

I have a flask restful api with an endpoint
api.add_resource(TestGet, '/api/1/test')
and I want to use the data from that endpoint to populate my jinja template. But everytime I try to call it in a sample route like this
#app.route('/mytest')
def mytest():
t = get('http://localhost:5000/api/1/test')
It never returns anything and stays in a loop meaning it is doing something with the request and never returns. Is there a reason I am not able to call it within the same flask app? I am able to reach the endpoint on the browser and from another python REPL. Thoroughly confused why this would happen and why it never returns anything. At least expecting an error.
Here is the entire sample of what I am trying to run
from flask import Flask
from requests import get
app = Flask('test')
from flask_restful import Api, Resource
api = Api(app)
class TestGet(Resource):
def get(self):
return {'test': 'message'}
api.add_resource(TestGet, '/test')
#app.route('/something')
def something():
resp = get('http://localhost:5000//test').json
print(resp)
from gevent.wsgi import WSGIServer
WSGIServer(('', 5000), app).serve_forever()
Use app.run(threaded=True) if you just want to debug your program. This will start a new thread for every request.
Please see this SO thread with nice explanation of Flask limitations: https://stackoverflow.com/a/20862119/5167302
Specifically, in your case you are hitting this one:
The main issue you would probably run into is that the server is single-threaded. This means that it will handle each request one at a time, serially. This means that if you are trying to serve more than one request (including favicons, static items like images, CSS and Javascript files, etc.) the requests will take longer. If any given requests happens to take a long time (say, 20 seconds) then your entire application is unresponsive for that time (20 seconds).
Hence by making request from within request you are putting your application into deadlock.

how to capture data from flask and send it to other python function

So here is what I am trying to do.. I want to capture the response from user (which i take the from user from a web gui) and then send those responses to different python function for processing.
So here is what the flow looks like
Program ---> Flask APp --|
/\ |
|_____________________|
My program is like:
def call_flask():
call_hello()
and
def call_hello():
data = request.form
for data_tuple in data:
requests[data_tuple] = data[data_tuple]
return render_template('request_submitted.html')
I am interested in sending "requests" to the main program?
What is a clean way to do this..
Don't know if I understand it right... This "Program" is totally different thing and not the web interface you are talking about? If this is totally different thing, then what you can actually do it - after the flask is done with the request, you can have function which does what you want. So if the "Program" sits somewhere in the same machine, you can call process to run or it somehow start that.
Flask does have after_request function, which tells what needs to be done after each request is finished. Here could be a good place to call "Program". But of course then you need to know how you want to call. I can imagine you calling some other url with the json payload, or just calling system app with arguments. But this depends on you :)
But if the "Program" is just a web gui you are talking about, then you just obviously render the template and returning some variables to it, to be rendered.
Hope I got your question right ;)

How do I do JSONP with python on my webspace..?

I just checked my webspace and it's signature says: Apache/2.2.9 (Debian) mod_python/3.3.1 Python/2.5.2 mod_ssl/2.2.9 OpenSSL/0.9.8g
This give me hope that Python is somehow supported. Why is python listed twice? mod_python/3.3.1 AND Python/2.5.2 ???
There is a cgi-bin folder on my webspace.
What I want to do: I need to do a cross-site call to get some text-data from a server. The text-data is not JSON but I guess I should convert it to JSON (or is there an option to do cross-site without JSON?)
The python script gets the request for some JSONP. Depending on the request (I guess I should somehow parse the URL) the python script is to load the a requested text-data file from the webserver and wrap it in some JSON and return it.
Can somebody tell me how I do these three steps with python on my webspace?
First off, the signature isn't listing python twice. Its listing first the version of mod_python, which is an Apache web server plugin, then it is listing the version of the python interpreter on the system.
python cgi module - This is really an inefficient approach to writing python server code, but here it is. Ultimately you should consider one of the many amazing python web frameworks out there. But, using the cgi module, your response would always start with this:
print 'Content-Type: application/json\n\n'
Your python script would run on the server from an HTTP request. In that script you would check the request and determine the data you will want to serve from either the URL value or the query string.
At the very least you would just wrap your return value in a basic JSON data structure. The text data itself can just be a string:
import json
text_data = "FOO"
json_data = json.dumps({'text': text_data})
print json_data
# {"text": "FOO"}
For the JSONP aspect, you would usually check the query string to see if the request contains a specific name for the callback function the client wants, or just default to 'callback'
print "callback(%s);" % json_data
# callback({"text": "FOO"});
Returning that would be a JSONP type response, because when the client receives it, the callback is executed for the client.
And to conclude, let me add that you should be aware that python cgi scripts will need to start a brand new python interpreter process for every single request (even repeat requests from the same client). This can easily overwhelm a server under increased load. For this reason, people usually go with the wsgi route (mod_wsgi in apache). wsgi allows a persistant application to keep running, and handles ongoing requests.

Categories