'message': 'The method is not allowed for the requested URL.' - python

I am getting this error when I run my python script to make a call to my API:
{'message': 'The method is not allowed for the requested URL.'}
I cannot figure out why I am getting this error as I am using the exact code as the tutorial I am following.
Here is the call to my API:
import requests
BASE = "http://127.0.0.1:5000/"
response = requests.put(BASE + "video/1", {"likes": 10})
print(response.json())
And here is my API:
from flask import Flask
from flask_restful import Api, Resource, reqparse
app = Flask(__name__)
api = Api(app)
video_put_args = reqparse.RequestParser()
video_put_args.add_argument("name",type=str, help="t")
video_put_args.add_argument("views",type=int, help="t")
video_put_args.add_argument("likes",type=int, help="t")
videos = {}
class Video(Resource):
def get(self, video_id):
return videos[video_id]
def put(self, video_id):
args=video.args.parse_args()
return {videoid:args}
api.add_resource(Video, "/video/<int:video_id>")
if __name__ == "__main__":
app.run(debug=True)
Any help would be appreciated, thanks

Related

How to make rest API that responds to post(data=data,header=header) with python and flask

I am trying to make a rest API in python.flask and I want it to be responsive to python.requests.post(data=data,header=header). But every tutorial and website only shows me Postman and
An API that responds to python.requests.post(PARAMS=data,header=header) but "PARAMS" does not work for my case. I've tried using python.flask.request.get_json(), I've tried using python.flask.Resource, I've tried using another one here:-
from flask import Flask
from flask_restful import Resource, Api, reqparse
from json import loads as dictionary
from flask import request as req
app = Flask(__name__)
api = Api(app)
#app.route('/test', methods=['POST'])
def post(username,token,url):
# gotit=dictionary(gotit)
k = '{"name":'+username+',"password":'+token+',"link":'+url+'}'
print(k)
return k
if __name__ == '__main__':
app.run()#debug=True)
But all in vain. Please help me make an API that responds to this:- python.requests.post(data=data,header=header). And also help with the header thing.
Python.v3.8
Here's your code but with some modification:
Server Code:
from flask import Flask, jsonify, request
import requests
import json
app = Flask(__name__)
#app.route('/test', methods=['POST'])
def post():
# you will get that data in request.data you can simplify/jsonfiy
text = str(request.data)
t = request.data
return t
if __name__ == "__main__":
app.run(debug=True)
python.requests Code:
import requests
header = {
"Content-Type":"text/plain"
}
data = {
"username":"myName",
"password":"myPass",
"url":"myWeb"
}
d = requests.post(url='http://127.0.0.1:5000/test', data=data, headers=header)
#
print(d.content)
Response from server something like this:
response Screenshot
I'm Using Python 3.9.1
Hope it will help You:)

fetching data from Flask REST service from laravel

I am trying to pass the path of an xml file to a flask/Python based REST-microservice. When passing the url manually to the service, it works as intended. However, I have problems calling the service from my laravel project.
Call to python rest service from laravel:
function gpxToJson(){
url = "http://127.0.0.1:5000/convert?path=C:/xampp/htdocs/greenlaneAdventures/public/storage/gpx/OOCe4r5Mas8w94uGgEb8qYlI0T3ClZDoclcfrR7s.xml" ;
fetch(url).then(function (response){
var track = JSON.parse(response.json());
return track;
});
}
Python script:
import gpxpy
import pandas as pd
from flask_cors import CORS
from flask import Flask, request, make_response, render_template
from flask_restful import Resource, Api
# create empty web-application
app = Flask(__name__)
api = Api(app)
CORS(app)
# create necessary classes
class Converter(Resource):
def get(self):
# path passed as argument
file = request.args.get('path', '')
# parse gpx file
gpx = gpxpy.parse(open(file))
# define data
track = gpx.tracks[0]
segment = track.segments[0]
# load wanted data into a panda dataframe
data = []
segment_length = segment.length_3d()
for point_idx, point in enumerate(segment.points):
data.append([point.longitude, point.latitude, point.elevation,
point.time, segment.get_speed(point_idx)])
columns = ['Longitude', 'Latitude', 'Altitude', 'Time', 'Speed']
gpx_df = pd.DataFrame(data, columns=columns)
# convert dataframe to json
gpx_json = gpx_df.to_json(orient='index')
print(gpx_json)
#return the converted json (http response code 200 = OK. The request has suceeded)
headers = {"Content-Type": "application/json"}
return make_response(gpx_json, 200, headers)
api.add_resource(Converter, "/convert")
#error handling
#app.errorhandler(404)
def not_found():
"""Page not found."""
return make_response(
render_template("404.html"),
404
)
#app.errorhandler(400)
def bad_request():
"""Bad request."""
return make_response(
render_template("400.html"),
400
)
#app.errorhandler(500)
def server_error():
"""Internal server error."""
return make_response(
render_template("500.html"),
500
)
#main function call
if __name__ == "__main__":
app.run(debug=True)
When calling the function gpxToJson() by submitting a form, I get the following error message in firefox.

How to test Flask router methods with HTTPBasicAuth annotations

I'm new to Python and I try to implement REST API service on Flask. I faced with issue related to testing of my code. My Flask app looks something like that:
from flask import Flask, jsonify, make_response, request
from flask_httpauth import HTTPBasicAuth
import os
auth = HTTPBasicAuth()
#auth.get_password
def get_password(username):
if username == os.environ['SERVICE_KEY']:
return os.environ['SERVICE_PASS']
return None
#auth.error_handler
def unauthorized():
return make_response(jsonify({'error': 'Unauthorized access'}), 403)
app = Flask(__name__)
tweets = [
{
'id': 1,
'profileId': '1',
'message': 'My test tweet'
},
{
'id': 2,
'profileId': '1',
'message': 'Second tweet!'
}
]
#app.route('/api/v1/tweets', methods=['GET'])
#auth.login_required
def get_tweets():
return jsonify({'tweets': tweets}), 200
#app.errorhandler(404)
#auth.login_required
def not_found(error):
return make_response(jsonify({'error': 'Not found'}), 404)
if __name__ == '__main__':
app.run(debug=True)
And here is my test (currently it is only for not_found method):
import unittest
from app import app
class TestApp(unittest.TestCase):
def setUp(self):
self.app = app.test_client()
def test_404(self):
rv = self.app.get('/i-am-not-found')
self.assertEqual(rv.status_code, 404)
if __name__ == '__main__':
unittest.main()
But when I try to run test, it fails due to I get 'Unauthorized access' response:
>python test.py
F
======================================================================
FAIL: test_404 (__main__.TestApp)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test.py", line 25, in test_404
self.assertEqual(rv.status_code, 404)
AssertionError: 403 != 404
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures=1)
Which approach for testing route-methods are more correct to handle authorization? And how can I fix that failed test?
You need to create a custom header that includes your auth details and send it along with your request. Something like this:
from base64 import b64encode
...
headers = {'Authorization': 'Basic ' + b64encode("{0}:{1}".format(username, password))}
rv = self.app.get('/i-am-not-found', headers=headers)
...
import unittest
from app import app
class TestApp(unittest.TestCase):
def setUp(self):
self.app = app.test_client()
def test_404(self):
headers = {
'Authorization': 'Basic ' + b64encode("username:password")
}
rv = self.app.get('/i-am-not-found', headers=headers)
self.assertEqual(rv.status_code, 404)
if __name__ == '__main__':
unittest.main()
Your username and password is sent in the form username:password but is base64 encoded. If expanding this there are ways to make this simpler such as extracting into a function to always pass the header and externalising username/password for testing.
EDIT: Additionally I think you should be returning a 401 code here. 401 is usually used when credentials are incorrect, 403 is usually used when you have successfully authenticated yourself but do not have access to a resource. A very simplified example being logged into Facebook but being restricted from accessing another person's photo that is marked as private.

flask_dance + Google Search Console API searchAnalytics

I'm currently testing Google Search Console API and Flask Dance to do the oauth stuff.
It works great for getting the /sites, but i get an
ValueError: View function did not return a response
if i try to query searchAnalytics with /search
According to https://developers.google.com/webmaster-tools/search-console-api-original/v3/searchanalytics/query#try-it it must be POST + additonal data. e.g.:
json={'startDate':'2017-11-01','endDate':'2017-12-01'}
In https://developers.google.com/oauthplayground/ it works like this but with flask dance sadly not. any ideas?
import os
from werkzeug.contrib.fixers import ProxyFix
from flask import Flask, redirect, url_for
from flask_dance.contrib.google import make_google_blueprint, google
from raven.contrib.flask import Sentry
app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)
sentry = Sentry(app)
app.secret_key = os.environ.get("FLASK_SECRET_KEY", "supersekrit")
app.config["GOOGLE_OAUTH_CLIENT_ID"] = os.environ.get("GOOGLE_OAUTH_CLIENT_ID")
app.config["GOOGLE_OAUTH_CLIENT_SECRET"] = os.environ.get("GOOGLE_OAUTH_CLIENT_SECRET")
google_bp = make_google_blueprint(scope=["profile", "email", "https://www.googleapis.com/auth/webmasters"])
app.register_blueprint(google_bp, url_prefix="/login")
#app.route("/")
def index():
return "BlA BLA"
#app.route("/sites")
def sites():
if not google.authorized:
return redirect(url_for("google.login"))
resp = google.get("/webmasters/v3/sites")
siteEntry = resp.json()["siteEntry"]
result = ""
for site in siteEntry:
result = result + site["siteUrl"] + "</br>"
return result
#app.route("/search")
def search():
if not google.authorized:
return redirect(url_for("google.login"))
resp = google.post("/webmasters/v3/sites/https%3A%2F%2Fzrce.eu/searchAnalytics/query", json={'startDate':'2017-11-01','endDate':'2017-12-01'})
print(resp)
if __name__ == "__main__":
app.run()
All API routes should always return something even if its an empty response.
Simply return a response, it can be "" or resp.

Python requsts.post returning 405 error: The method is not allowed for the requested URL

Howdie do,
I'm just running a simple flask API call.
The flask API will take a XML request in and then parse the XML and print it to the terminal screen.
However, everytime I do this, I'm receiving
The method is not allowed for the requested URL
The Flask script is:
__author__ = 'Jeremy'
from flask import Flask
from flask import request
import xmltodict
app = Flask(__name__)
#app.route('/', methods=['POST'])
def parsexml():
xmlrequest = xmltodict.parse(request.data)
print xmlrequest
if __name__ == '__main__':
app.run()
The script that sends the XML is:
__author__ = 'Jeremy'
import requests
xml = """
<dtc:GetShipmentUpdates>
<dtc:GetShipmentUpdatesRequest>
<dtc:SearchStartTime>2015-07-12T12:00:00</dtc:SearchStartTime>
<dtc:SearchEndTime>2015-07-12T12:30:00</dtc:SearchEndTime>
</dtc:GetShipmentUpdatesRequest>
</dtc:GetShipmentUpdates> """
headers = {'Content-Type': 'application/xml'}
r = requests.post('http://127.0.0.1:5000/', data=xml, headers=headers)
print r.content
Does anyone know why this is happening and if so, how can I send a POST request to my flask application running on 127.0.0.1:5000
You aren't returning anything from parsexml. Try returning some content:
#app.route('/', methods=['POST'])
def parsexml():
xmlrequest = xmltodict.parse(request.data)
print xmlrequest
return "Thanks for the data!"
Howdie do,
You can't send POST requests to /
So I changed it to go to the following:
__author__ = 'Jeremy'
from flask import Flask
from flask import request
import xmltodict
app = Flask(__name__)
#app.route('/')
def say_hello():
return "Say goodbye Jeremy"
#app.route('/api', methods=['POST'])
def parsexml():
xmlrequest = xmltodict.parse(request.data)
return xmlrequest
if __name__ == '__main__':
app.run(host='0.0.0.0', port=int("80"))
Work now

Categories