Attempting to check an in-memory list, plant_list[] against a JSON payload from an api.
If the incoming payload's dict name matches inside of plant_list the if should fire off.
Instead my script only returns null
Please point out my mistakes.
The JSON sent over the api call is:
{ "name":"swizz", "days": "7", "price": 2.00 }
Source Code
from flask import Flask, request
from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app)
#app.route('/', methods=['GET', 'POST'])
def home():
return 'Tiny'
plant_list = []
class Plant(Resource):
def get(self, name):
return {'Name':name}, 200
def post(self, name):
payload = request.get_json()
for x in range(0, len(plant_list)):
if payload['name'] == plant_list[x]['name']:
return {'message': f'''Item {payload['name']} already stored in database.'''}
else:
plant_list.append(payload)
return plant_list, 201
api.add_resource(Plant, '/plant/<string:name>')
if __name__ == '__main__':
app.run(port=9004, debug=True)
You can test for key in dict simply by: if key_name in my_dict:... So, if "price" in plant_list[x]:
You are setting plant_list as a global. If you want to use that inside a Class, you should define it inside the function in your class:
plant_list = []
class Plant(Resource):
....
def post(self, name):
global plant_list
....
Not sure why you need it as a global variable. Perhaps you want:
class Plant(Resource):
plant_list = []
....
def post(self, name):
....
Related
I'm trying to implement a REST API with Flask-RESTful. My API contains 4 requests: GET, POST, PUT, DELETE. Everything works perfectly except for the PUT request. It keeps returning Status Code 404, which the requested URL is not found. I'm using Postman to test my API. Here is my code. Can any show me where did I do it wrong? Thank you!
# Small API project using Flask-RESTful
from flask import Flask, request
from flask_restful import Resource, Api, reqparse
from flask_jwt import JWT, jwt_required
app = Flask(__name__)
# Encrypted key
app.secret_key = "Nam Dao"
api = Api(app)
students = []
class Student(Resource):
parser = reqparse.RequestParser()
parser.add_argument("major", type=str, required=True, help="This field cannot be left blank")
def get(self, name):
# filter function will return a filter object
# next function will get the "next" student in the filter object.
# if the Next function does not return anything => return None.
for student in students:
if student["name"] == name:
return student, 200
return {"message": "student not found"}, 404
def post(self, name):
if next(filter(lambda x: x["name"] == name, students), None) is not None:
return {"message": f"A student with the name {name} already exists"}, 400
request_data = self.parser.parse_args()
print(request_data)
student = {"name": name, "major": request_data["major"]}
students.append(student)
return student, 201
def delete(self, name):
for student in students:
if student["name"] == name:
students.remove(student)
return {"message": "Item deleted"}, 200
return {"message": "No student found"}, 204
def put(self, name):
data = request.get_json()
for student in students:
if student["name"] == name:
student["major"] = data["major"]
return {"message": "Student Major Changed"}, 200
student = {"name": data["name"], "major": data["major"]}
students.append(student)
return {"message": "Student Added"}, 200
api.add_resource(Student, "/student/<string:name>")
class StudentsList(Resource):
def get(self):
return {"students": students}, 200
api.add_resource(StudentsList, "/students")
if __name__ == '__main__':
app.run(debug=True)
I recheck my URL again and I was missing a letter, that's why it returns 404 Status Code. It was a very silly mistake. Everything works just fine
I'm trying to build an api using Flask-restplus and Flask-Flask-Injector.
I searched and couldn't find an example on these two together.
All examples are on Flask, not the restplus one.
I tried to build using the following:
``
from flask import Flask
from flask_restplus import Api, Resource
from flask_injector import FlaskInjector, Injector, inject, singleton
app = Flask(__name__)
app.secret_key = "123"
api = Api(app=app)
class MyConf():
def __init__(self, val: int):
self.val = val
class MyApi(Resource):
#inject
def __init__(self, conf: MyConf):
self.val = conf.val
def get(conf: MyConf):
return {'x': conf.val}, 200
api.add_resource(MyApi, '/myapi')
def configure(binder):
myConf = MyConf(456)
binder.bind(
MyConf,
to=MyConf(456),
scope=singleton
)
binder.bind(
MyApi,
to=MyApi(myConf)
)
FlaskInjector(app=app, modules=[configure])
app.run(port=555, debug=True)
I'm new to python, actually I don't know if this usage of Flask-Injector is correct, so I'm getting this error when calling the api (myapi) with get method using the browser:
injector.CallError: Call to MyApi.init(conf=<main.MyConf object at 0x0000026575726988>, api=) failed: init() got an unexpected keyword argument 'api' (injection stack: [])
I was able to solve this with the help of an issue I opened on github, here's the updated working version of the code:
app = Flask(__name__)
app.secret_key = "123"
api = Api(app=app)
class MyConf():
def __init__(self, val: int):
self.val = val
class MyApi(Resource):
#inject
def __init__(self, conf: MyConf, **kwargs): # <- here just added **kwargs to receice the extra passed `api` parameter
self.val = conf.val
# Don't know if really needed
super().__init__(**kwargs)
def get(conf: MyConf):
return {'x': conf.val}, 200
api.add_resource(MyApi, '/myapi')
def configure(binder):
myConf = MyConf(456)
binder.bind(
MyConf,
to=MyConf(456),
scope=singleton
)
# No need to bind the resource itself
#binder.bind(
# MyApi,
# to=MyApi(myConf)
#)
FlaskInjector(app=app, modules=[configure])
app.run(port=555, debug=True)
I am trying to pass params to the URL in flask, but I can not get them to show up for anything.
#logout.route('/logout')
def logout_page():
current_provider = current_oauth_user.get_provider()
return render_template('index.html', provider=current_provider)
I expect to see /logout?provider=facebook but I just get /logout
Right now I am doing this:
#logout.route('/logout')
def logout_page():
provider = request.args.get('provider')
current_provider = current_oauth_user.get_provider()
if not provider and current_provider:
return redirect(url_for('logout.logout_page',
provider=current_provider))
return render_template('index.html')
but that just seems so terrible.
You should return some value using '/logout' path.
So at first, you use render_template(index.html) under def main(). Then you create def logout_page() and return some value ( in your case is current_provider).
#app.route('/')
def main():
return render_template('index.html')
#app.route('/logout')
def logout_page():
current_provider = current_oauth_user.get_provider()
return current_provider
if __name__=="__main__":
app.run(port=8000)
I am new to Flask and I need some help for my school work.
I am trying to build a simple ToDo list system using flask-restful.
My current code looks like this:
class ToDoList(Resource):
'''TODO LIST'''
operation = ['delete']
decorators = [auth.login_required, advertise('operation')]
def post(self):
"""remove all item in the TODO list"""
operation = request.args.get('op')
if operation == 'delete':
collection2.delete_many({})
return {'Success': 'OK'}, 200
return {'Error':'Illegal Operation'}, 400
def get(self):
"""return a list of the TODO name"""
list_1 = collection2.find()
list_2 = []
for each in list_1:
list_2.append(JSONEncoder().encode(each))
return {'list':list_2}, 200
It works, but I want only the post method to require authentication, and get method without authentication so anyone can acquire the list without login. I am using the flask-restful I don't know how to give the decorators separately to each function.
I used flaskrestplus to do basic authentication. All the required authorizations are provided as an authorizations dictionary. Then they are passed to the API.
Also the authorizations can be applied at the method level using
#api.doc(security='basicAuth')
The validation logic (can be ldap validation or db validation) can be writted in a decorator called requires_Auth. This decorator is invoked using
decorators = [requires_Auth]
Complete code
from flask import Flask, request
from flask_restplus import Api, Resource
from functools import wraps
def requires_Auth(f):
#wraps(f)
def decorator(*args, **kwargs):
auth = request.authorization
if auth:
print "inside decorator", auth.username,auth.password
return f(*args, **kwargs)
else:
return "Login required!!!!",401
return decorator
authorizations = {
'basicAuth': {
'type': 'basic',
'in': 'header',
'name': 'Authorization'
}
}
api = Api(app, version='1.0',
authorizations=authorizations
)
ns = api.namespace('/', description='Authentication API')
#ns.route('/withDecorator')
class HelloWorldWithDecorator(Resource):
decorators = [requires_Auth]
#api.doc(security='basicAuth')
def get(self):
return {'hello': 'world'}
api.add_namespace(ns)
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5001)
From Flask-RESTful documentation [1]:
Alternatively, you can specify a dictionary of iterables that map to HTTP methods and the decorators will only apply to matching requests.
def cache(f):
#wraps(f)
def cacher(*args, **kwargs):
# caching stuff
return cacher
class MyResource(restful.Resource):
method_decorators = {'get': [cache]}
def get(self, *args, **kwargs):
return something_interesting(*args, **kwargs)
def post(self, *args, **kwargs):
return create_something(*args, **kwargs)
In your case it would be:
method_decorators = {'post': [auth.login_required]}
I have a class that doesn't extend webapp.RequestHandler, and I can't use self.response.out.write(), I get:
AttributeError: Fetcher instance has no attribute 'response'
If I extend webapp.RequestHandler (I thought it would work), I get:
AttributeError: 'Fetcher' object has no attribute 'response'
How can I use that method properly? Sometimes print doesn't work either; I just get a blank screen.
EDIT:
app.yaml:
application: fbapp-lotsofquotes
version: 1
runtime: python
api_version: 1
handlers:
- url: .*
script: main.py
source (the problematic line is marked with #<- HERE):
import random
import os
from google.appengine.api import users, memcache
from google.appengine.ext import webapp, db
from google.appengine.ext.webapp import util, template
from google.appengine.ext.webapp.util import run_wsgi_app
import facebook
class Quote(db.Model):
author = db.StringProperty()
string = db.StringProperty()
categories = db.StringListProperty()
#rating = db.RatingProperty()
class Fetcher(webapp.RequestHandler):
'''
Memcache keys: all_quotes
'''
def is_cached(self, key):
self.fetched = memcache.get(key)
if self.fetched:
print 'ok'#return True
else:
print 'not ok'#return False
#TODO: Use filters!
def fetch_quotes(self):
quotes = memcache.get('all_quotes')
if not quotes:
#Fetch and cache it, since it's not in the memcache.
quotes = Quote.all()
memcache.set('all_quotes',quotes,3600)
return quotes
def fetch_quote_by_id(self, id):
self.response.out.write(id) #<---------- HERE
class MainHandler(webapp.RequestHandler):
def get(self):
quotes = Fetcher().fetch_quotes()
template_data = {'quotes':quotes}
template_path = 'many.html'
self.response.out.write(template.render(template_path, template_data))
class ViewQuoteHandler(webapp.RequestHandler):
def get(self, obj):
self.response.out.write('viewing quote<br/>\n')
if obj == 'all':
quotes = Fetcher().fetch_quotes()
self.render('view_many.html',quotes=quotes)
else:
quotes = Fetcher().fetch_quote_by_id(obj)
'''for quote in quotes:
print quote.author
print quote.'''
def render(self, type, **kwargs):
if type == 'single':
template_values = {'quote':kwargs['quote']}
template_path = 'single_quote.html'
elif type == 'many':
print 'many'
self.response.out.write(template.render(template_path, template_values))
'''
CREATORS
'''
class NewQuoteHandler(webapp.RequestHandler):
def get(self, action):
if action == 'compose':
self.composer()
elif action == 'do':
print 'hi'
def composer(self):
template_path = 'quote_composer.html'
template_values = ''
self.response.out.write(template.render(template_path,template_values))
def post(self, action):
author = self.request.get('quote_author')
string = self.request.get('quote_string')
print author, string
if not author or not string:
print 'REDIRECT'
quote = Quote()
quote.author = author
quote.string = string
quote.categories = []
quote.put()
def main():
application = webapp.WSGIApplication([('/', MainHandler),
(r'/view/quote/(.*)',ViewQuoteHandler),
(r'/new/quote/(.*)',NewQuoteHandler) ],
debug=True)
util.run_wsgi_app(application)
if __name__ == '__main__':
main()
You're not routing to Fetcher when you initialize a WSGIApplication. Rather, you create an instance manually in other handlers. Thus, App Engine will not initialize your request and response properties. You can manually do so in from the handlers you route to, such as MainHandler and ViewQuoteHandler. E.g.:
fetcher = Fetcher()
fetcher.initialize(self.request, self.response)
quotes = fetcher.fetch_quotes()
Note that fetcher really doesn't have to be a RequestHandler. It could be a separate class or function. Once you have request and response objects, you can pass them around as you choose.