I am currently developing a site which uses Angular JS for the front-end framework and Flask for the RESTful API. I am using vagrant to host the LAMP server where my app resides. The API was tested using curl, and it works exactly as I want it to.
I get the following error when I run the app:
`*GET http://localhost:5000/choreographer/api/v1.0/choreographers net::ERR_CONNECTION_REFUSED
(anonymous function) # angular.js:10722
sendReq # angular.js:10515
serverRequest # angular.js:10222
processQueue # angular.js:14745
(anonymous function) # angular.js:14761
Scope.$eval # angular.js:15989
Scope.$digest # angular.js:15800
Scope.$apply # angular.js:16097
(anonymous function) # angular.js:12226
eventHandler # angular.js:3298*`
I originally thought this might be a CORS issue, so I tried using $http.jsonp(). This produced the same error. I know that there is something which is hindering my ability to access the API, but I do not know what or how to fix it.
My AngularJS module is as follows:
angular.module('myApp.choreographer', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/choreographer', {
templateUrl: 'choreographer/choreographer.html',
controller: 'choreographerCtrl'
});
}])
.factory('choreographerService', function($resource) {
return $resource('http://localhost:5000/choreographer/api/v1.0/choreographers');
})
.controller('choreographerCtrl', function($scope, choreographerService) {
var choreographers = choreographerService.query(function() {
console.log(choreographers);
}); //query() returns all the entries
});
The flask API is as follows:
\#!env/bin/python
from flask import Flask, jsonify
from flask import abort
from flask import request
app = Flask(__name__)
#app.route('/')
def index():
return "Hello World!"
choreographers = [
{
"id":1,
"firstName": "Danny",
"lastName": "Boy",
"email": "email#email.edu",
"bio": "Biography for Danny."
},
{
"id":2,
"firstName": "Jessica",
"lastName": "Martin",
"email": "helloworld#smu.edu",
"bio": "Biography text for Jessica"
},
{
"id":3,
"firstName": "John",
"lastName": "Doe",
"email": "test#pleasework.com",
"bio": "Biography text for John"
}
]
#app.route('/choreographer/api/v1.0/choreographers', methods=['GET'])
def get_choreographers():
return jsonify({'choreographers': choreographers})
#app.route('/choreographer/api/v1.0/choreographer/<int:choreographer_id>', methods=['GET'])
def get_choreographer(choreographer_id):
choreographer = [choreographer for choreographer in choreographers if choreographer['id'] == choreographer_id]
if len(choreographer) == 0:
abort(404)
return jsonify({'choreographer':choreographer[0]})
#app.route('/choreographer/api/v1.0/choreographer', methods=['POST'])
def add_choreographer():
if not request.json or not 'firstName' in request.json:
abort(400)
choreographer = {
'id': choreographers[-1]['id'] + 1,
'firstName': request.json['firstName'],
'lastName': request.json.get('lastName',""),
'email': request.json['email'],
'bio': request.json['bio'],
}
choreographers.append(choreographer)
return jsonify({'choreographers': choreographer}),201
#app.route('/choreographer/api/v1.0/choreographers/<int:choreographer_id>', methods=['PUT'])
def update_choreographer(choreographer_id):
choreographer = [choreographer for choreographer in choreographers if choreographer['id'] == choreographer_id]
if len(choreographer) == 0:
abort(404)
if not request.json:
abort(400)
if 'firstName' in request.json and type(request.json['firstName']) != unicode:
abort(400)
if 'lastName' in request.json and type(request.json['lastName']) is not unicode:
abort(400)
choreographer[0]['firstName'] = request.json.get('firstName', choreographer[0]['firstName'])
choreographer[0]['lastName'] = request.json.get('lastName', choreographer[0]['lastName'])
choreographer[0]['email'] = request.json.get('email', choreographer[0]['email'])
choreographer[0]['bio'] = request.json.get('bio', choreographer[0]['bio'])
return jsonify({"choreographer": choreographer[0]})
#app.route('/choreographer/api/v1.0/choreographers/<int:choreographer_id>', methods=['DELETE'])
def delete_choreographer(choreographer_id):
choreographer = [choreographer for choreographer in choreographers if choreographer['id'] == choreographer_id]
if len(choreographer) == 0:
abort(404)
choreographers.remove(choreographer[0])
return jsonify({'result':True})
if __name__ == '__main__':
app.run(debug=True)
My Angular tests the first GET method in the Flask API
Related
I'm trying to marshal a simple data structure in Flask, as below:
{
"globalNum": 1.23,
"perResultData": [
{
"string1": "test string",
"num1": 1.25
},
{
"string1": "test",
"num1": 1.22
}
]
}
I'm modelling that structure like this:
testmodel = api.model('Model', {
'globalNum': fields.Float,
'perResultData': fields.List(fields.Nested({
"string1": fields.String,
"num1": fields.Float
}))
})
When I try this setup (as per minimum failing code below), if I browse to localhost I get a warning 'No API definition provided.' and the Flask console shows:
File "/home/mikea/.local/lib/python3.6/site-packages/flask_restplus/swagger.py", line 574, in register_model
if name not in self.api.models:
TypeError: unhashable type: 'dict'
Flask works perfectly when I comment out the '#api.marshal_with(testmodel)' line.
Can someone shed some light on what I'm doing wrong, please? Thanks very much
Full code:
from flask_restplus import Resource, Api,fields
app = Flask(__name__)
api = Api(app)
testmodel = api.model('Model', {
'globalNum': fields.Float,
'perResultData': fields.List(fields.Nested({
"string1": fields.String,
"num1": fields.Float
}))
})
#api.route('/')
class incomingRequest(Resource):
#api.marshal_with(testmodel)
def post(self):
return {"globalNum":3.2,
"perResultData":[
{
"string1": "test string",
"num1": 1.25
},
{
"string1": "test",
"num1": 1.22
}
]}
if __name__ == '__main__':
app.run(debug=True)
The answer was here - https://github.com/noirbizarre/flask-restplus/issues/292
When nesting models, you have to wrap them in the model class, like the below:
testmodel = api.model('Model', {
'globalNum': fields.Float,
'perResultData': fields.List(fields.Nested(api.model({
"string1": fields.String,
"num1": fields.Float
})))
})
Using IOS, Visual Studio Code, Flask, VirtualEnv....
I've just started playing with Flask and Flutter. I've created a locally hosted flask server which returns users via the api and I'm trying to access the api with Flutter with my usb attached IOS device. When I try an api hosted on the internet, I get output on my phone, however when I point to the local API it does not look like it's hitting the server, I get no response in the flask server log stating a request was made. What am I doing wrong?
Via my browser I can navigate to 127.0.0.1:5000/users and get the following output. I expect this to appear on my phone:
[{"name": "Nick", "age": 42, "occupation": "Network Engineer"},
{"name": "Elvin", "age": 32, "occupation": "Business Analyst"},
{"name": "Nick", "age": 22, "occupation": "Test Analyst"}]
Here is my flask server code:
from flask import Flask
from flask_restful import Api, Resource, reqparse
from flask import jsonify
import json
app = Flask(__name__)
api = Api(app)
users = [
{
"name": "Nick",
"age": 42,
"occupation": "Network Engineer"
},
{
"name": "Elvin",
"age": 32,
"occupation": "Business Analyst"
},
{
"name": "Nick",
"age": 22,
"occupation": "Test Analyst"
}
]
class User(Resource):
def get(self, name):
for user in users:
if(name ==user["name"]):
return user, 200
return "User not found#, 404"
def post(self, name):
parser = reqparse.RequestParser()
parser.add_argument("age")
parser.add_argument("occupation")
args = parser.parse_args()
for user in users:
if(name == user["name"]):
return "User with name {} already exist".format(name), 400
user = {
"name": name,
"age": args["age"],
"occupation": args["occupation"]
}
users.append(user)
return user, 201
def put(self, name):
parser = reqparse.RequestParser()
parser.add_argument("age")
parser.add_argument("occupation")
args = parser.parse_args()
for user in users:
if(name == user["name"]):
user["age"] = args["age"]
user["occupation"] = args["occupation"]
return user, 200
user = {
"name": name,
"age": args["age"],
"occupation": args["occupation"]
}
users.append(user)
return user, 201
def delete(self, name):
global users
users = [user for user in users if user["name"] != name]
return "{} is deleted.".format(name), 200
#app.route('/users', methods=['GET'])
def getUsers():
return json.dumps(users)
api.add_resource(User, "/user/<string:name>")
app.run(debug=True)
Here is my pubspec.yaml
name: apitest2
description: A new Flutter project.
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
http: ^0.12.0+2
cupertino_icons: ^0.1.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
Here is my API.dart - changing from 127... to my local IP address doesn't make a difference
import 'dart:async';
import 'package:http/http.dart' as http;
const baseUrl = "http://127.0.0.1:5000";
//const baseUrl = "http://192.168.86.24:5000";
//const baseUrl = "https://jsonplaceholder.typicode.com";
class API {
static Future getUsers() {
var url = baseUrl + "/users";
return http.get(url);
}
}
Here is my User.dart
class User {
String name;
int age;
String occupation;
User(String name, int age, String occupation) {
this.name = name;
this.age = age;
this.occupation = occupation;
}
User.fromJson(Map json)
: name = json['name'],
age = json['age'],
occupation = json['occupation'];
Map toJson() {
return {'name': name, 'age': age, 'occupation': occupation};
}
}
Here is my Main.dart
import 'dart:convert';
import 'package:apitest2/API.dart';
import 'package:apitest2/User.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
build(context) {
return MaterialApp(
debugShowCheckedModeBanner: true,
title: 'My Http App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyListScreen(),
);
}
}
class MyListScreen extends StatefulWidget {
#override
createState() => _MyListScreenState();
}
class _MyListScreenState extends State {
var users = new List<User>();
_getUsers() {
API.getUsers().then((response) {
setState(() {
Iterable list = json.decode(response.body);
users = list.map((model) => User.fromJson(model)).toList();
});
});
}
initState() {
super.initState();
_getUsers();
}
dispose() {
super.dispose();
}
#override
build(context) {
return Scaffold(
appBar: AppBar(
title: Text("User List"),
),
body: ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return ListTile(title: Text(users[index].name));
},
));
}
}
Main Idea
If we want to make HTTP requests to our API from other computers or devices connected to our LAN, we should use the development computer IP address, 0.0.0.0 (for IPv4 configurations) or :: (for IPv6 configurations) as the desired IP address for our development server.
If we specify 0.0.0.0 as the desired IP address for IPv4 configurations, the development server will listen on every interface on port 5000.
Refer following solution, which also address a similar problem:
https://stackoverflow.com/a/62371660/10031056
I wrote a python code for the dialog flow using the flask and webhook. I am able to get the response but it not displayed in the dialog flow. This code running perfectly.
CODE:
# import os
import json
# import urllib
import datetime
from config import Configuration
from swe_commands import SweCommands
from flask import Flask, request, make_response
# Flask application should start in global layout
app = Flask(__name__)
#app.route('/webhook', methods=['POST'])
def webhook():
req = request.get_json(silent=True, force=True)
print "Request:"
print json.dumps(req, indent=1)
res = make_webhook_result(req)
res = json.dumps(res, indent=1)
print "Response:"
print res
r = make_response(res)
r.headers['Content-Type'] = 'application/json'
return r
def make_webhook_result(req):
# if req.get("queryResult").get("action") != "nakshatra":
# return {}
swe_path = Configuration.swe_path()
date_and_time = str(datetime.datetime.now())[:19]
panchang_dictionary = SweCommands.find_panchang(swe_path, date_and_time)
result = req.get("queryResult")
parameters = result.get("parameters")
angam = parameters.get("nakshatra")
nakshatra = panchang_dictionary[angam]
speech = "Current nakshatra is %s" % nakshatra
source = "Panchangam"
output = {'speech': speech, "displayText": speech, "source": source}
return output
if __name__ == '__main__':
port = 5000
print "Starting app in port %s" % port
app.run(debug=True, port=port, host='127.0.0.1')
REQUEST:
**{
"queryResult": {
"fulfillmentMessages": [
{
"text": {
"text": [
""
]
}
}
],
"allRequiredParamsPresent": true,
"parameters": {
"nakshatra": "nakshatra"
},
"languageCode": "en",
"intentDetectionConfidence": 0.6725314,
"action": "nakshatra",
"intent": {
"displayName": "PanchangFind",
"name": "projects/my-project-1536557558293/agent/intents/6d1d46bf-3787-48cd-9b45-0766d5f2b107"
},
"queryText": "What is nakshatra"
},
"originalDetectIntentRequest": {
"payload": {}
},
"session": "projects/my-project-1536557558293/agent/sessions/08857865-1d08-2eef-5d4f-83b92107f09b",
"responseId": "2137da9d-23a9-4735-aec2-7adb7ae52d85-9cc28bb4"
}**
RESPONSE:
**{
"displayText": "Current nakshatra is Shravana",
"speech": "Current nakshatra is Shravana",
"source": "Panchangam"
}**
But it not get displayed in the dialog flow panel? Whether I have to set any parameters for dialog flow panel to receive the response in a dialog flow. Please let me know.
I got an answer to this. When we use V1 in dialog flow, the response key is displayText. But in V2 the response key is fulfillmentText. When I added the response key in this name it able to detect the output.
I am in the middle of creating todo app integreted with Slack. I need to use dialog.open property of slack.
I managed to go through slack api tutorial however can not finally understand how dialogs work in integration with external systems. I created code which runs after slash command in slack. It should open dialog and show it to user, however it doesn't. I printed some parts of code to see what happens inside - looks like whole code works and server returns 200.
#app.route('/helpdesk', methods=['POST'])
def helpdesk():
print(request.form)
api_url = 'https://slack.com/api/dialog.open'
user_id = request.form['user_id']
trigger_id = request.form['trigger_id']
dialog = {
"token": "J1llSAeQAxNyw8yc37xuEsad",
"trigger_id": trigger_id,
"dialog": {
"callback_id": "ryde-46e2b0",
"title": "Request a Ride",
"submit_label": "Request",
"notify_on_cancel": True,
"state": "Limo",
"elements": [
{
"type": "text",
"label": "Pickup Location",
"name": "loc_origin"
},
{
"type": "text",
"label": "Dropoff Location",
"name": "loc_destination"
}
]
}
}
print(dialog)
requests.post(api_url, data=dialog)
return make_response()
I expect to see dialog window after writing slash command in slack.
What I see in prints:
ImmutableMultiDict([('token', 'J1llSAeQAxNyw8yc37xuEsad'), ('team_id', 'TKWQ5QP7Y'), ('team_domain', 'team-learningslack'), ('channel_id', 'CKH7RSZPC'), ('channel_name', 'slackflask'), ('user_id', 'UKN9KU7JM'), ('user_name', 'konrad.marzec1991'), ('command', '/musi'), ('text', ''), ('response_url', 'https://hooks.slack.com/commands/TKWQ5QP7Y/664885241506/ABjpMYmTWrnXpSBoGMpaJtOV'), ('trigger_id', '669947662833.676821839270.6c4bddd1418d3d4f2c8626f7c9accdf7')])
{'token': 'J1llSAeQAxNyw8yc37xuEsad', 'trigger_id': '669947662833.676821839270.6c4bddd1418d3d4f2c8626f7c9accdf7', 'dialog': {'callback_id': 'ryde-46e2b0', 'title': 'Request a Ride', 'submit_label': 'Request', 'notify_on_cancel': True, 'state': 'Limo', 'elements': [{'type': 'text', 'label': 'Pickup Location', 'name': 'loc_origin'}, {'type': 'text', 'label': 'Dropoff Location', 'name': 'loc_destination'}]}}
127.0.0.1 - - [26/Jun/2019 00:15:35] "POST /helpdesk HTTP/1.1" 200 -
You had 2 issues in your code:
you need to use an access token, not a verification token in the call
to dialog.open
you need to send the dialog definition as JSON, not as as form array
I made these additional changes
- Added code for using a slack token defined as environment variable
- Use the get() method to access form parameters in from the request
- Added code to show the API response from dialog.open
Here is a corrected version of your code:
import os
import requests
from flask import Flask, json, request
app = Flask(__name__) #create the Flask app
#app.route('/helpdesk', methods=['POST'])
def helpdesk():
api_url = 'https://slack.com/api/dialog.open'
trigger_id = request.form.get('trigger_id')
dialog = {
"callback_id": "ryde-46e2b0",
"title": "Request a Ride",
"submit_label": "Request",
"notify_on_cancel": True,
"state": "Limo",
"elements": [
{
"type": "text",
"label": "Pickup Location",
"name": "loc_origin"
},
{
"type": "text",
"label": "Dropoff Location",
"name": "loc_destination"
}
]
}
api_data = {
"token": os.environ['SLACK_TOKEN'],
"trigger_id": trigger_id,
"dialog": json.dumps(dialog)
}
res = requests.post(api_url, data=api_data)
print(res.content)
return make_response()
if __name__ == '__main__':
app.run(debug=True, port=8000) #run app in debug mode on port 8000
I'm writing a small API, and wanted to print a list of all available methods along with the corresponding "help text" (from the function's docstring). Starting off from this answer, I wrote the following:
from flask import Flask, jsonify
app = Flask(__name__)
#app.route('/api', methods = ['GET'])
def this_func():
"""This is a function. It does nothing."""
return jsonify({ 'result': '' })
#app.route('/api/help', methods = ['GET'])
"""Print available functions."""
func_list = {}
for rule in app.url_map.iter_rule():
if rule.endpoint != 'static':
func_list[rule.rule] = eval(rule.endpoint).__doc__
return jsonify(func_list)
if __name__ == '__main__':
app.run(debug=True)
Is there a better -- safer -- way of doing this? Thanks.
There is app.view_functions. I think that is exactly what you want.
from flask import Flask, jsonify
app = Flask(__name__)
#app.route('/api', methods = ['GET'])
def this_func():
"""This is a function. It does nothing."""
return jsonify({ 'result': '' })
#app.route('/api/help', methods = ['GET'])
def help():
"""Print available functions."""
func_list = {}
for rule in app.url_map.iter_rules():
if rule.endpoint != 'static':
func_list[rule.rule] = app.view_functions[rule.endpoint].__doc__
return jsonify(func_list)
if __name__ == '__main__':
app.run(debug=True)
Here's mine:
#app.route("/routes", methods=["GET"])
def getRoutes():
routes = {}
for r in app.url_map._rules:
routes[r.rule] = {}
routes[r.rule]["functionName"] = r.endpoint
routes[r.rule]["methods"] = list(r.methods)
routes.pop("/static/<path:filename>")
return jsonify(routes)
Gives:
{
"/": {
"functionName": "index",
"methods": [
"HEAD",
"OPTIONS",
"GET"
]
},
"/gen": {
"functionName": "generateJobs",
"methods": [
"HEAD",
"OPTIONS",
"GET"
]
},
"/jobs": {
"functionName": "getJobs",
"methods": [
"HEAD",
"OPTIONS",
"GET"
]
},
"/jobs/submit": {
"functionName": "postJob",
"methods": [
"POST",
"OPTIONS"
]
},
"/jobs/update/<id>": {
"functionName": "updateJob",
"methods": [
"POST",
"OPTIONS"
]
},
"/routes": {
"functionName": "getRoutes",
"methods": [
"HEAD",
"OPTIONS",
"GET"
]
}
}
from flask import Flask, jsonify
app = Flask(__name__)
#app.route('/api/help', methods=['GET'])
def help():
endpoints = [rule.rule for rule in app.url_map.iter_rules()
if rule.endpoint !='static']
return jsonify(dict(api_endpoints=endpoints))
if __name__ == '__main__':
app.run(debug=True)