PokeAPI & Flask: Combining different properties on API - python-3.x

API beginner here,
I'm creating an API that calls both a character name and their description with one ENDPOINT. So far I have the data appearing at separate endpoints.
Goal: Getting output format ('http://127.0.0.1:5000/v1/pokemon/string:name') to look similar to this:
{ "name": "pichu", "description": "It is not yet skilled at storing electricity.It may send out a jolt if amused or startled."}
from flask import Flask, jsonify, Response
from flask_restful import Resource, Api, fields, marshal_with
import requests, json
app = Flask(__name__)
api = Api(app)
# Prints all Pokemon via JSON
#app.route('/v1/pokemon/all', methods=['GET'])
def poke_names():
data = []
name_url = "https://pokeapi.co/api/v2/pokemon?limit=151"
while True:
resp = requests.get(name_url)
json = resp.json()
data.extend(json.get('results', []))
name_url = json.get('next')
if not name_url: break
return jsonify(data)
#app.route('/v1/pokemon/<string:name>/title', methods=['GET'])
def get_poke(name):
return jsonify({'name': name})
#flavor Text ie pokemon description
#app.route('/v1/pokemon/<int:pokemon_id>', methods=['GET'])
def get_description(pokemon_id):
descrip_url = f"https://pokeapi.co/api/v2/pokemon-species/{pokemon_id}"
r = requests.get(descrip_url)
json_blob = r.json()
flav_text = extract_descriptive_text(json_blob)
return jsonify({'description': flav_text})
def extract_descriptive_text(json_blob, language='en'):
text = []
for f in json_blob['flavor_text_entries']:
if f['language']['name'] == language:
text.append(f['flavor_text'])
return text
#error occurs below
#app.route('/v1/pokemon/<string:name>')
def all_poke_data(name, flav_text):
return jsonify({'name':name, 'description':flav_text})
if __name__ == "__main__":
app.run(debug=True)
Error: When I try to combine them I get
TypeError: all_poke_data() missing 1 required positional argument: 'flav_text'
Thank you for any pointers provided!

Figured it out!
Just add this function, which is a combination of both route functions
#app.route('/v1/pokemon/<string:name>')
def get_poke(name):
descrip_url = f"https://pokeapi.co/api/v2/pokemon-species/{name}"
r = requests.get(descrip_url)
json_blob = r.json()
flav_text = extract_descriptive_text(json_blob)
return jsonify({'name': name},{'description': flav_text})

Related

Why is my POST getting a 405? Python-Flask API

I'm currently writing an API in Flask, and am currently trying to me my POST request to work. Ideally, it would add a band to the DB with a band_ID, name, genre, number of gigs, and a rating. For some reason, running the proper POST request in postman returns a 405. I didn't even know an API *I made * would tell me I don't have access to a POST I'm writing. Do I need to change anything to make it have access?
from flask import Flask, request
from flask_restful import Api, Resource
import sqlite3
app = Flask(__name__)
api = Api(app)
class Band(Resource):
def get(self, band_id):
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute("SELECT * FROM bands WHERE band_id=?", (band_id,))
result = c.fetchone()
if result:
return {"message": result}
else:
return {"message": "Band not found"}
def post(self):
data = request.get_json()
if not all(key in data for key in ('band_name', 'band_genre', 'gigs', 'rating')):
return {"message": "Missing data"}
band_name = data['band_name']
band_genre = data['band_genre']
gigs = data['gigs']
rating = data['rating']
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute("INSERT INTO bands (band_name,band_genre,gigs,rating) VALUES (?,?,?,?)", (band_name,band_genre,gigs,rating))
conn.commit()
return {"message": "Success"}
api.add_resource(Band, '/bands/<int:band_id>')
if __name__ == "__main__":
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute("DROP TABLE IF EXISTS bands")
c.execute("""CREATE TABLE IF NOT EXISTS bands (
band_id INTEGER PRIMARY KEY,
band_name TEXT,
band_genre TEXT,
gigs INTEGER,
rating INTEGER
)""")
conn.commit()
app.run(debug=True)
I've tried changing the call on postman and fiddling around with my add.resource lines but to no avail. Totally lost on what to do next.

Unable to display csv file output at API endpoint

I have just started working on Flask and Python. I am building an API server in which I am trying to read a csv file and display the output of csv file on /osdata at port 8080.
There might be some issue in returning the data from function. Any help would be appreciated.
from flask import Flask, request
from flask_restful import Resource, Api
import json, csv
app = Flask(__name__)
app.config["DEBUG"] = True
api = Api(app)
#app.route('/', methods=['GET'])
def home():
return "1 2 3 Start"
#app.route('/osdata', methods=['GET'])
def osdata():
with open("Output_data.csv", "r") as f:
data = csv.reader(f, delimiter = "~")
line_count = 0
for row in data:
print(row)
line_count += 1
return(row)
if __name__ == '__main__':
app.run(port=8080)

Python3 Flask: "Function() missing 1 required positional argument: 'test_output'"

I'm just starting with FLASK and stumbled upon this error:
test() missing 1 required positional argument: 'test_output'
Why is this happening? The functions is declared before calling it and usually this error means that the argument while calling the function is missing.
def foo(x):
print (x)
foo(x)
So this is working, why doesn't it work in my script with flask?
Here is my "full" code:
from flask import Flask, jsonify, request
from flask_pymongo import PyMongo
app = Flask(__name__)
#app.config ['MONGO_DBNAME'] = 'DBfoo'
app.config['MONGO_URI'] = 'mongodb://127.0.0.1:27017/Test'
mongo = PyMongo(app)
#app.route('/TestRouteGet', methods=['GET', 'POST'])
def test(test_output):
print (test_output)
def get_Test():
collection = mongo.db.TestCol
if request.method == 'POST':
test_input = "Test BlaBla"
test(test_input)
if __name__ == '__main__':
app.run(debug=True)
When sending a POST request I should have the test_output ("Test Blabla") printed in the console.
Thanks for your time.
Your function expects test_output argument, you should get this argument from the url string http://flask.pocoo.org/docs/1.0/quickstart/#url-building
#app.route('/TestRouteGet/<test_output>', methods=['GET', 'POST'])
Then you can make a request to /TestRouteGet/insert_your_string and your function will print received string.

Python is throwing "syntax error" while using #app.route

Python is throwing "Syntax Error" when I compile the code below.
File "app.py", line 11
#app.route('/')
^
SyntaxError: invalid syntax
I'm not sure what it means.
from flask import Flask, render_template
import urllib.request
import json
import time
app = Flask(__name__ ,template_folder='template')
namep = "PewDiePie"
namet = "TSeries"
key = "MY_API_KEY"
#app.route("/")
for x in range(5):
time.sleep(2)
datat = urllib.request.urlopen("https://www.googleapis.com/youtube/v3/channels?part=statistics&forUsername="+namep+"&key="+key).read()
datap = urllib.request.urlopen("https://www.googleapis.com/youtube/v3/channels?part=statistics&forUsername="+namet+"&key="+key).read()
subt = json.loads(datat)["items"][0]["statistics"]["subscriberCount"]
subsp = json.loads(datap)["items"][0]["statistics"]["subscriberCount"]
def main():
return render_template('index.html', pewds_sub = subsp, tseries_sub = subt)
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=80)
Any help regarding this is appreciated.
Thanks!
You must define the function after the route decorator, i.e. after #app.route
Updated code
#app.route("/")
def function_main():
#all logics here
return render_template('index.html', pewds_sub = subsp, tseries_sub = subt)
Make sure to process your calculations inside function else try to pass those argument in defined function.
from flask import Flask, render_template
import urllib.request
import json
import time
app = Flask(__name__ ,template_folder='template')
namep = "PewDiePie"
namet = "TSeries"
key = "MY_API_KEY"
#app.route("/")
def main():
for x in range(5):
time.sleep(2)
datat = urllib.request.urlopen("https://www.googleapis.com/youtube/v3/channels?part=statistics&forUsername="+namep+"&key="+key).read()
datap = urllib.request.urlopen("https://www.googleapis.com/youtube/v3/channels?part=statistics&forUsername="+namet+"&key="+key).read()
subt = json.loads(datat)["items"][0]["statistics"]["subscriberCount"]
subsp = json.loads(datap)["items"][0]["statistics"]["subscriberCount"]
return render_template('index.html', pewds_sub = subsp, tseries_sub = subt)
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=80)
in my case,
I initiated a try block just above for the database connection and forget to put catch block, that's why I have encountered this error.
so I suggest anyone facing the same error,
should check the code above #app.route('/') because if you have import flask
properly this should work pretty fine syntax error in this statement usually indicates that you might have a problem above this line and not at that line.

Invalid syntax within Lambda using Python 3.6 to pull from DynamoDB

I can't, for the life of me, figure out what is wrong with the following four lines of code.
def getAssetExistance(asset, element, table):
dynamoTable = dynamo.Table(table)
response = dynamoTable.query(KeyConditionExpression=Key(element).eq(asset)
return bool(response)
I am running this through aws Lambda and the log on cloudwatch is telling me the error is on the return line. This is the error (line 24 is the return line):
Syntax error in module 'lambda_function': invalid syntax (lambda_function.py, line 24)
In case this helps at all, here is the rest of the code:
################################
# Slack Lambda handler.
################################
import boto3
import os
import logging
import urllib
# Grab data from the environment.
BOT_TOKEN = os.environ["BOT_TOKEN"]
ASSET_TABLE = os.environ["ASSET_TABLE"]
REGION_NAME = os.getenv('REGION_NAME', 'us-east-1')
dynamo = boto3.client('dynamodb', region_name=REGION_NAME)
# Define the URL of the targeted Slack API resource.
SLACK_URL = "https://slack.com/api/chat.postMessage"
def getAssetExistance(asset, element, table):
dynamoTable = dynamo.Table(table)
response = dynamoTable.query(KeyConditionExpression=Key(element).eq(asset)
return bool(response)
def lambda_handler(data, context):
# Slack challenge answer.
if "challenge" in data:
return data["challenge"]
# Grab the Slack channel data.
slack_event = data['event']
slack_user = slack_event["user"]
slack_text = slack_event["text"]
channel_id = slack_event["channel"]
slack_userID = slack_user["ID"]
slack_reply = ""
# Ignore bot messages.
if "bot_id" in slack_event:
logging.warn("Ignore bot event")
else:
# Start data sift.
if slack_text.startswith("!networth"):
slack_reply = "Your networth is: "
elif slack_text.startwith("!price"):
command,asset = text.split()
slack_reply = "The price of a(n) %s is: " % (asset)
elif slack_text.startwith("!Addme"):
if not getAssetExistance(slack_userID, userID, ASSET_TABLE):
slack_reply = "Adding user: %s(%s)" % (slack_user, slack_userID)
dynamo.update_item(TableName=ASSET_TABLE,
Key={'userID':{'S':'slack_userID'},
AttributeUpdates= {
'resources':{
'Action': 'ADD',
'Value': {'N': '1000'}
}
}
)
else
slack_reply = "User %s(%s) already exists" % (slack_user, slack_userID)
# We need to send back three pieces of information:
data = urllib.parse.urlencode(
(
("token", BOT_TOKEN),
("channel", channel_id),
("text", slack_reply)
)
)
data = data.encode("ascii")
# Construct the HTTP request that will be sent to the Slack API.
request = urllib.request.Request(
SLACK_URL,
data=data,
method="POST"
)
# Add a header mentioning that the text is URL-encoded.
request.add_header(
"Content-Type",
"application/x-www-form-urlencoded"
)
# Fire off the request!
urllib.request.urlopen(request).read()
# Everything went fine.
return "200 OK"
Hopefully I am doing something dumb; I am pretty new to all this. Any help is much appreciated it. Thanks!
You skipped closed round bracket in this line:
response = dynamoTable.query(KeyConditionExpression=Key(element).eq(asset)
replace this line by:
response = dynamoTable.query(KeyConditionExpression=Key(element)).eq(asset)

Resources