Issue with bad request syntax with flask - python

I am testing/attempting to learn flask, and flast_restful. This issue I get is:
code 400, message Bad request syntax ('name=testitem')
main.py:
from flask import Flask,request
from flask_restful import Api, Resource, reqparse
app = Flask(__name__)
api = Api(app)
product_put_args = reqparse.RequestParser()
product_put_args.add_argument("name", type = str, help = "Name of the product")
product_put_args.add_argument("quantity", type = int, help = "Quantity of the item")
products = {}
class Product(Resource):
def get(self, barcode):
return products[barcode]
def put(self, barcode):
args = product_put_args.parse_args()
return {barcode: args}
api.add_resource(Product, "/product/<int:barcode>")
if(__name__) == "__main__":
app.run(debug = True)
and my
test.py
import requests
base = "http://127.0.0.1:5000/"
response = requests.put(base + "product/1", {"name": "testitem"})
print(response.json())
I have attempted to reform mat and change around both files to figure out what is sending the issue, I feel like it is something simple, but if you can help me, I bet this will help me and many others that are trying to start creating a rest API.

You need to add the location information to the RequestParser by default it tries to parse values from flask.Request.values, and flask.Request.json, but in your case, the values need to be parsed from a flask.request.form. Below code fixes your error
from flask import Flask,request
from flask_restful import Api, Resource, reqparse
app = Flask(__name__)
api = Api(app)
product_put_args = reqparse.RequestParser()
product_put_args.add_argument("name", type = str, help = "Name of the product", location='form')
product_put_args.add_argument("quantity", type = int, help = "Quantity of the item", location='form')
products = {}
class Product(Resource):
def get(self, barcode):
return products[barcode]
def put(self, barcode):
args = product_put_args.parse_args()
products[barcode] = args['name']
return {barcode: args}
api.add_resource(Product, "/product/<int:barcode>")
if(__name__) == "__main__":
app.run(debug = True)

Related

How to instantiate a class correctly using Depency Injector in a Flask app?

In my Flask app, I'm using Dependency Injection and here's what my app looks like. I have a service which uses S3 as a datastore and I'm trying to instantiate my app with the service injected (which is injected with the S3 client). However, it doesn't look like the S3 client is correctly instantiated or I'm doing something wildly different.
containers.py
class Container(containers.DeclarativeContainer):
wiring_config = containers.WiringConfiguration(modules=[".routes", ".scheduler"])
config = providers.Configuration()
s3_config = dict()
s3_config["path"], s3_config["filters"] = config.get("s3_bucket"), [("member_status_nm", "=", "ACTIVE")]
s3_repository = providers.Singleton(S3Repository, s3_config)
my_service = providers.Factory(
MyService, config, S3Repository
)
Here's my S3Repository:
import logging
import sys
import time
import some_library as lib
class S3Repository:
def __init__(self, s3_config):
self.path, self.columns, self.filters = \
s3_config.get("path", ""), s3_config.get("columns", []), s3_config.get("filters", [])
def fetch(self):
# execute fetch
result = lib.some_fetch_method(self.path, self.columns, self.filters)
return result
and MyService:
import #all relevant imports here
class MyService:
def __init__(self, config: dict, s3_repository: S3Repository) -> None:
logging.info("HealthSignalService(): initializing")
self.config = config["app"]["health_signal_service"]
# prepare s3_repository for the service
self.s3_repository = s3_repository
self.s3_repository.columns, self.s3_repository.filters, self.s3_repository.path = \
["x","y"], ["x1","y1"], "file_path"
def fetch_data(self) -> None:
try:
summary_result = self.s3_repository.fetch()
except (FileNotFoundError, IOError) as e:
print("failure")
return summary_result
def get_data(memberId):
sth = self.fetch_data()
return sth.get(memberId)
and finally tying it together in my routes.py:
#inject
#auth.login_required
def get_signals(
my_service: MyService = Provide[
Container.my_service
],
):
content = request.json
member_id = content["memberId"]
result = my_service.get_signals(member_id)
return jsonify(result)
When I hit my API endpoint I see this error:
summary_result = self.s3_repository.fetch()
TypeError: fetch() missing 1 required positional argument: 'self'
How do I correctly initialize my S3 client while using dependency injection?

Problem with POST Method on my Flask APP on Python

i have a problem with my flask app thaht i'm trying to create,
i wrote a POST Method to take arguments from HTTP and write them to a table.
here's my code:
from flask import Flask
from flask_restful import Resource, Api, reqparse
import pandas as pd
import ast
import sqlalchemy
# SQLAlchemy connectable
engine = sqlalchemy.create_engine("mssql+pymssql://my_connection_string")
conn = engine.connect()
app = Flask(__name__)
api = Api(app)
class Samples(Resource):
def get(self):
data = pd.read_sql_table('DBLIST_DATA', engine)
data = data.to_dict() # convert dataframe to dict
return {'data': data}, 200 # return data and 200 OK
def post(self):
parser = reqparse.RequestParser() # initialize
parser.add_argument('NODE_NO_data', required=True) # add args
parser.add_argument('BLOCK_NAME_data', required=True)
parser.add_argument('BLOCK_TYPE_data', required=True)
args = parser.parse_args() # parse arguments to dictionary
# read our SQL Table
data = pd.read_sql_table('DBLIST_DATA', engine)
#Check if Value Exists
if args['NODE_NO_data'] in list(data['NODE_NO_data']):
return {
'message': f"'{args['NODE_NO_data']}' already exists."
}, 409
else:
# create new dataframe containing new values
new_data = pd.DataFrame({
'NODE_NO_data': [args['NODE_NO_data']],
'BLOCK_NAME_data': [args['BLOCK_NAME_data']],
'BLOCK_TYPE_data': [args['BLOCK_TYPE_data']],
'locations': [[]]
})
# add the newly provided values
data = data.append(new_data, ignore_index=True)
data.to_sql('DBLIST_DATA', index=False) # save back to SQL Table
return {'data': data.to_dict()}, 200 # return data with 200 OK
api.add_resource(Samples, '/samples') # add endpoints
if __name__ == '__main__':
app.run() # run app
when i try to POST via Postman the following values:
127.0.0.1:5000/samples/?NODE_NO_data=1&BLOCK_NAME_data=Machine&BLOCK_TYPE_data=Vertical
i'm getting a 404 not found error.
can someone please tell me what i'm doing wrong?
Thanks!
You could just remove the last / of your request URL http://127.0.0.1:5000/samples.

Flask-caching a function using blueprints

I am doing an app and I am using the Blueprints structure. My code is running okay, but I got this error while trying to implment flask-caching into one function.
The error returned is:
AttributeError: 'Blueprint' object has no attribute 'cache'
Does anybody has a light of solution in here to make the cache happens to this function?
Here is a piece of my code:
from flask import render_template, redirect, request, Blueprint
from cache import store_weather, number_of_views, cached_weather, cache
import json, requests
bp = Blueprint('bp', __name__, url_prefix="/weather")
main = Blueprint('main', __name__)
api_key = "42fbb2fcc79717f7601238775a679328"
#main.route('/')
def hello():
views = 5
max_views = number_of_views()
return render_template('index.html', cached_weather=cached_weather, max_views=max_views, views=views)
#bp.route('/', methods=['GET'])
def weather():
clean_list_cache()
if request.args.get('max').isdigit():
views = int(request.args.get('max'))
else:
views = 5
try:
city_name = request.args.get('city')
if city_name not in cached_weather:
uri = 'http://api.openweathermap.org/data/2.5/weather?q={city}&appid={key}'.format(city=city_name,key=api_key)
# On that point, we bring the data from the Open Weather API
rUrl = requests.get(uri)
# The temperature of the Open Weather API is in Kelvin, so, we have to subtract 273.15 to transform
# it into Celsius degrees
temperature = str(round((json.loads(rUrl.content)['main'])['temp']-273.15))+" °C"
name = json.loads(rUrl.content)['name']
description = json.loads(rUrl.content)['weather'][0]['description']
city_data = { "temp":temperature, "name":name, "desc":description }
store_weather(city_data)
max_views = number_of_views(views)
return render_template('weather.html', cached_weather = cached_weather, error_rec_city = False, max_views=max_views, views=views)
except KeyError:
max_views = number_of_views(views)
return render_template('weather.html', cached_weather=cached_weather, error_rec_city = True, max_views=max_views, views=views)
#bp.cache.cached(timeout=30, key_prefix='list_cache')
def clean_list_cache():
cached_weather.clear()
The error occurs, as you are trying to call cache on your blueprint: #bp.cache.cached. An example from the docs how to use cache is:
#app.route("/")
#cache.cached(timeout=50)
def index():
return render_template('index.html')
So you have to squeeze the cache decorator between your app decorator and the function

How to use SELECT query based on method parameter in Flask restplus Api?

I want to handle a GET request in my Flask REST API.The request will include List parameter and I use this to be a typical GET request:
https://localhost:5000/organisation?List=1
this request, will return all of Organisation Model information. Organisation is a Model class for a table of my MySQL database(by peewee).
I want to enter PrivenceId parameter in request and will return all of Organisation Model information where Organisation.PrivencedId == PrivenceId parameter, But I encounter the following Error:
TypeError: 'Organisation' object is not iterable
my code (OrganisationController.py file) is:
from flask_restplus import Resource, reqparse
from Models.Organisation import Organisation
from flask import request
# Define parser and request args
parser = reqparse.RequestParser()
parser.add_argument('List', type=int)
parser.add_argument('ProvinceId', type=int)
class List(Resource):
def get(self):
args = parser.parse_args()
List = args['List']
ProvinceId = args['ProvinceId']
if List :
Organisations = Organisation.select()
Ls = [dict (
ID = c.ID,
Title = c.Title,
Code = c. Code,
OrgEnumId = c.OrgEnumId,
ProvinceId = c.ProvinceId,
CityId = c.CityId,
Address = c.Address,
Phone = c.Phone,
) for c in Organisations
]
return dict(Organisations = Ls)
elif (ProvinceId) :
Organisations = Organisation.select().where
(
Organisation.ProvinceId ==args['ProvinceId']
).get()
Ls = [dict (
ID = c.ID,
Title = c.Title,
Code = c. Code,
OrgEnumId = c.OrgEnumId,
ProvinceId = c.ProvinceId,
CityId = c.CityId,
Address = c.Address,
Phone = c.Phone,
) for c in Organisations
]
return dict(Organisations = Ls)
and boot.py file for run api is :
from flask import Flask
from flask_restplus import Api
from Controllers import OrganisationController
app = Flask(__name__)
api = Api(app)
api.add_resource(OrganisationController.List, '/organisation')
if __name__ == "__main__":
app.run ('127.0.0.1', 5000, True)
Could you help me?
I changed this line of my code and solved my problem:
Organisations = Organisation.select().where
(
Organisation.ProvinceId ==args['ProvinceId']
)

Python / Flask / MongoEngine DateTimeField

First of I'm new to python and flask. I've searched around and tried something things to no avail. I have a model that has a DateTimeField as one of the members, let's call it "created_at". When I go to return the query set as JSON I see this for the field
...
"created_at": {
"$date": 1412938697488
}
...
Is there anyway to get the output, either through a custom JSON encoder, etc to get it to look like this :
"created_at": "2014-10-10T07:33:04Z",
Any guidance or suggestions would be greatly appreciated.
Thanks!
Here is an example using flask and flask-mongoengine to get a date as ISO 8601 string
import datetime
from bson.json_util import dumps
from flask import Flask, Response, request
from flask_mongoengine import MongoEngine
app = Flask(__name__)
db = MongoEngine()
class Movie(db.Document):
name = db.StringField(required=True, unique=True)
casts = db.ListField(db.StringField(), required=True)
genres = db.ListField(db.StringField(), required=True)
created_at = db.DateTimeField(default=datetime.datetime.utcnow)
#app.route('/movies')
def get_movies():
movies = Movie.objects()
movies_list = []
for movie in movies:
movie_dict = movie.to_mongo().to_dict()
movie_dict['created_at'] = movie.created_at.isoformat()
movies_list.append(movie_dict)
movies_josn = dumps(movies_list)
return Response(movies_josn, mimetype="application/json", status=200)
#app.route('/movies', methods=['POST'])
def add_movie():
body = request.get_json()
movie = Movie(**body).save()
id = movie.id
return {'id': str(id)}, 200
if __name__ == '__main__':
app.config['MONGODB_SETTINGS'] = {
'host': 'mongodb://localhost/movie-bag'
}
db.init_app(app)
app.run()

Categories