I am using flask restful on the server and need to use dill in order to dump a function to a binary and send it to the server
I am using this code to create the request
import inspect
import dill
import requests
def f():
a = 1
v = 2
return 1
b = dill.dumps(f, protocol=None)
requests.post("http://localhost:5000/server", data={"func": b})
and using this code on the server
from flask_restful import Resource, Api, reqparse
from flask import app
from flask import Flask
import dill
app = Flask(__name__)
api = Api(app)
class S(Resource):
def post(self):
parser = reqparse.RequestParser()
parser.add_argument("func", type=bytes, location="form")
try:
args = parser.parse_args()
print(dill.loads(args["func"])())
print(1)
except Exception as e:
print(e)
print(2)
api.add_resource(S, '/server')
if __name__ == '__main__':
app.run(debug=True, host="0.0.0.0", port=5000)
I keep geting errors about request that the server could not understand,
I tried marking the type as bytes, bytearray, str
I tried sending it in data, json and params
all without any luck.
What am i missing here?
Related
I believe I have the same problem as described here: Flask-Limiter does not work with Flask-Restful API-based application. But I still can't get it to work. Here's my problem:
I have an app.py where I import all my REST-API endpoints. I use flask-RESTful resources as described in this guide: https://flask-restful.readthedocs.io/en/latest/quickstart.html
I use the "Flask-Limiter" library for rate limiting: https://flask-limiter.readthedocs.io/en/stable/. The rate-limiter gets instantiated in a separate file, not inside app.py because this would create circular references between app.py and the REST-API endpoints. I think this could be the cause of my problem.
This is the rate-limiter file (located in: /controller/helpers/rate_limiter.py)
from flask import current_app
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
limiter = Limiter(
current_app,
key_func=get_remote_address
)
This is the app.py file (located in: /):
from flask import Flask
from flask_restful import Api
from controller.actions.my_endpoint import MyEndpoint
flask_app = Flask(__name__)
api = Api(flask_app)
api.add_resource(MyEndpoint, '/endpoint')
flask_app.run(debug=True, use_reloader=True, host='0.0.0.0', port=8000)
And finally this is an example of an endpoint (located in: /controller/actions/my_endpoint):
from flask_restful import reqparse, Resource
from controller.helpers.rate_limiter import limiter
class MyEndpoint(Resource):
decorators = [limiter.limit("1/minute", methods=["POST"])]
def __init__(self):
self.parser = reqparse.RequestParser()
self.parser.add_argument(
"someData", type=int, nullable=False, required=True)
def post(self):
data = self.parser.parse_args(strict=True)
someData = data.someData
return "Got your message {0}".format(someData), 200
I would expect that after the first request I would get response 429 because the rate limit of 1/minute is reached but it doesn't do that.
However, when I instantiate the limiter inside app.py and set a default rate-limit, it works (getting that error 429):
from flask import Flask
from flask_restful import Api
from controller.db_actions.my_endpoint import MyEndpoint
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
flask_app = Flask(__name__)
limiter = Limiter(
flask_app,
key_func=get_remote_address,
default_limits=["1 per minute"]
)
api = Api(flask_app)
api.add_resource(MyEndpoint, '/endpoint')
flask_app.run(debug=True, use_reloader=True, host='0.0.0.0', port=8000)
Question: I think I'm doing something wrong with instantiating the limiter. What is it? :)
Using just the Flask server with Python, the following get request works:
from flask import Flask, request
app = Flask(__name__)
class Result(Resource):
def get(self):
image_id = request.headers.get('image_id')
api.add_resource(Result, '/results')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=int(os.getenv('PORT', 5000)))
However, using Waitress, the following does not work (image_id is None):
from waitress import serve
from flask import Flask, request
app = Flask(__name__)
class Result(Resource):
def get(self):
image_id = request.headers.get('image_id')
api.add_resource(Result, '/results')
if __name__ == '__main__':
serve(app, host="0.0.0.0", port=int(os.getenv('PORT', 5000)))
POST and other GET requests work fine, it's just GET with headers that doesn't work. Anyone have any ideas?
I had the same issue, after searching around I found this issue on GitHub. Apparently it is a security feature and you should not use _ in your header. So you should rename your header to image-id or something else without a _ character for it to work.
the api should include one function called "write text to file" and inputs a string parameter
as for the function to write to the disk I have no problem and I implemented the code my problem is how to set the rest API using python.
EDIT:
this is my code:
from flask import (
Flask,
render_template
)
import SocketServer
import SimpleHTTPServer
import re
app = Flask(__name__, template_folder="templates")
#app.route('/index', methods=['GET'])
def index():
return 'Welcome'
#app.route('/write_text_to_file', methods=['POST'])
def write_text_to_file():
f = open("str.txt", "w+")
f.write("hello world")
f.close()
if __name__ == '__main__':
app.run(debug=True)
anyhow when I try to test my rest api:
http://127.0.0.1:5000/write_text_to_file
I am getting the following error:
Now I'm trying to test my rest-api , however how can I make my code to start the server and to the test the post request api, this is my test_class:
import requests
import unittest
API_ENDPOINT="http://127.0.0.1:5000/write_text_to_file"
class test_my_rest_api(unittest.TestCase):
def test_post_request(self):
"""start the server"""
r = requests.post(API_ENDPOINT)
res = r.text
print(res)
also when runnning my request using postman I am getting internal_server_error:
You're doing a GET request for this url, but you've specified that this endpoint can only accept POST:
#app.route('/write_text_to_file', methods=['POST'])
Also, the SocketServer and SimpleHTTPServer imports are not needed with Flask.
The method is not allowed because Chrome (or any browser) makes GET requests.
Whereas, you defined it as POST
#app.route('/write_text_to_file', methods=['POST'])
Either change it to a GET method, or use a tool such as POSTMan to perform other HTTP call types
I am new to API, and get a tasks of creating POST API. I have created a code somehow.
I want to add data to the hello.txt through post API, So how will I do it?
Here is my code:
import flask
from flask import request, jsonify
app = flask.Flask(__name__)
app.config["DEBUG"] = True
#app.route('/api/v1/resources/messages', methods = ['POST'])
def api_message():
if request.headers['Content-Type'] == 'text/plain':
return "Text Message: " + request.data
elif request.headers['Content-Type'] == 'application/octet-stream':
return "Binary message written!"
elif request.headers['Content-Type'] == 'application/json':
f = open('F:\Asif_Ahmed\Projects\api\hello.txt',"w")
f.write(request.data)
f.close()
return "JSON Message: " + json.dumps(request.json)
else:
return "415 Unsupported Media Type ;)"
app.run()
from flask import Flask, jsonify, render_template, request #import flask library
from flask_basicauth import BasicAuth # import flask library for create basic authentication if needed
from flask_cors import CORS # import flask library Cross-Origin Resource Sharing that is a mechanism that uses additional HTTP headers to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin
app = Flask(__name__)
CORS(app) #set-up cors for my app
#if you want use basic authentication you need set-up username and password
app.config['BASIC_AUTH_USERNAME'] = 'admin'
app.config['BASIC_AUTH_PASSWORD'] = 'password'
basic_auth = BasicAuth(app)#set-up username and password for my app but in this case I'm not specifying yet in which API use them
#app.route('/api/v1/resources/add_messages', methods=['POST'])#create my POST api
#basic_auth.required# set-up basic authentication for this API, comment out if not needed
def update_credential ():
json_credential=request.get_json()#get the JSON sent via API
print (json_credential["message"])#get the node "message" of my JSON
###########
#code to write in your file, you need write the json_credential["message"]
###########
return ("ok")
if __name__ == '__main__':
app.run(host='0.0.0.0', port=1024, threaded=True)#start my flask app with local_host IP and specific port, if you don't specify the port it will run in the default port
In this case the JSON Input should be:
{"message":"your text"}
Please let me know if something is not clear, I even try this code on my local and the JSON is passed without problems.....
So you need run your python script and see that the API is running, if you had no JSON to send and was just a simple API that give back information you should have used even Chrome but in this case that you need send some JSON data I would advice you to use Postman.
See screenshot example:
I have a python file which defines some endpoints using flask each doing some computation and return a JSON (POST method). I want to do unit testing on this in order to do this I want to be able to access the app I created in one python file in another file so I can test my endpoints.
I see a lot of this on the internet :
from source.api import app
from unittest import TestCase
class TestIntegrations(TestCase):
def setUp(self):
self.app = app.test_client()
def test_thing(self):
response = self.app.get('/')
assert <make your assertion here>
It doesn't explain how I can define and access my app in another file. This might be a stupid question but I really don't see how.
My app is defined as follows:
from flasgger import Swagger
from flask import Flask, jsonify, request
from flask_cors import CORS
import os
def init_deserializer_restful_api():
# Initiate the Flask app
app = Flask(__name__)
Swagger(app)
CORS(app)
# Handler for deserializer
#app.route("/deserialize", methods=['POST'])
def handle_deserialization_request():
pass
I have many other end points in this fashion. Should i just do:
import my_file_name
Thanks!!
Check out this question: What does if __name__ == "__main__": do?
As long as you have that in your python program, you can both treat it as a module and you can call it directly.