How can I make a Swift HTTP POST hit a Flask server? - python

I am trying to post some data to a Flask server, whose code is the following:
#app.route('/tasks', methods=['POST'])
def create_task():
if not request.json or not 'title' in request.json:
abort(400)
task = {
'title': request.json['title'],
'description': request.json.get('description', ""),
}
return jsonify({'task' : task}), 201
When I run this, it works fine, and I can make POST requests successfully using curl, with the expected behavior on the back end above and the expected return value in command line. I want to make a post to this server using Swift, however, and am having trouble with that. I have followed the tutorial detailing this behavior here. In particular, I put the code in my AppDelegate.swift so it is executed as soon as the app launches. The full code is in the link posted, but for reference I am also posting it below:
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
var request = NSMutableURLRequest(URL: NSURL(string: "http://localhost:4567/login"))
var session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
var params = ["username":"jameson", "password":"password"] as Dictionary<String, String>
var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
println("Response: \(response)")
var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Body: \(strData)")
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSDictionary
// Did the JSONObjectWithData constructor return an error? If so, log the error to the console
if(err != nil) {
println(err!.localizedDescription)
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: '\(jsonStr)'")
}
else {
// The JSONObjectWithData constructor didn't return an error. But, we should still
// check and make sure that json has a value using optional binding.
if let parseJSON = json {
// Okay, the parsedJSON is here, let's get the value for 'success' out of it
var success = parseJSON["success"] as? Int
println("Succes: \(success)")
}
else {
// Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: \(jsonStr)")
}
}
})
task.resume()
return true
}
However, when I launch this app, I have the following logged in my xcode
Response: <NSHTTPURLResponse: 0x7fc4dae218a0> { URL: http://localhost:5000/task } { status code: 404, headers {
"Content-Length" = 26;
"Content-Type" = "application/json";
Date = "Tue, 07 Oct 2014 19:22:57 GMT";
Server = "Werkzeug/0.9.6 Python/2.7.5";
} }
Body: {
"error": "Not found"
}
Succes: nil
I've been working with this and tinkering with the input, it seems that the back end is fine, but I'm wondering what is wrong with this front end, unfortunately Swift documentation is for the moment fairly moot on this point and seems to be the only solution floating around for RESTful API calls at the moment.

Your flask route is '/tasks' and you're trying to post to http://localhost:5000/task. Is that a typo, or are you a victim of failure to pluralize?

Related

Fetch JSON.parse: unexpected end of data at line 1 column 1 of the JSON data fast api

Hi i got a python fast api backend server.
#app.get("/getName")
async def getName() -> JSONResponse:
data_sniffer = DataSniffer()
data = json.dumps(data_sniffer.get_data())
print(data)
return JSONResponse(content=data,headers={'content-type':'application/json'})
this is the console output of data :{"first_name": "test"}
My Frontend Code looks like this
useEffect(() => {
async function query() {
const options = {
method: 'GET',
mode: 'no-cors',
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application-json',
},
};
const res = await fetch('http://127.0.0.1:3000/getName', options);
console.log(res);
const data = await res.json();
console.log(data);
}
query();
});
but i get following error message SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data
my network response looks like this:
"{"first_name": "test"}"
Has anyone a clue why fetch cant parse the json?
For anyone who has the same issue what worked for me is I moved my Backend folder to the root directory of my Frontend and removed the mode no-cors of the fetch request. I installed the no cors app and now it works. I think the mode no-cors broke my request.

How to get Api access in Swift?

I have created a program in python where I scrape a value from a 'wind' website. Everything works OK, but I wanted to try to build the same app in Swift, but when I try to run the program, it gives this error: "Unauthorized API access!"
But scraping with python works good... maybe because python uses json? can someone help me to find the mistake in my Swift code?
This is my python WORKING code:
import requests
headers = {'Referer' : 'https://www.windguru.cz/station/219'}
r = requests.get('https://www.windguru.cz/int/iapi.php? q=station_data_current&id_station=219&date_format=Y-m- d%20H%3Ai%3As%20T&_mha=f4d18b6c', headers = headers).json()
print(r)
print(r['wind_max'])
The output is the wind.
This is my swift code:
import UIKit
import SwiftSoup
class ViewController: UIViewController {
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let myURLString = "https://www.windguru.cz/int/iapi.php? q=station_data_current&id_station=219&date_format=Y-m- d%20H%3Ai%3As%20T&_mha=f4d18b6c"
guard let myURL = URL(string: myURLString) else { return }
do {
let myHTMLString = try String(contentsOf: myURL, encoding: .utf8)
let htmlcontent = myHTMLString
print(myHTMLString)
do {
let doc = try SwiftSoup.parse(htmlcontent)
do {
let element = try doc.select("title").first()
}
}
}catch let error {
print("error: \(error)")
}
}
This gives the API Access error.
for people who want to know the answer:
override func viewDidLoad() {
super.viewDidLoad()
let headers: HTTPHeaders = [
"Referer" : "https://www.windguru.cz/station/219"
]
Alamofire.request("https://www.windguru.cz/int/iapi.php?q=station_data_current&id_station=219&date_format=Y-m-d%20H%3Ai%3As%20T&_mha=f4d18b6c", headers: headers).responseJSON { response in
debugPrint(response)
}

Minimum example for replying to a message via BotFramework's REST API?

Within my Python webapp for the Microsoft Botframework, I want to reply to a message with a REST API call to /bot/v1.0/messages.
When experimenting with the emulator on my local machine, I realized that the minimum payload for the REST call is something like:
{
"text": "Hello, Hello!",
"from": {
"address": "MyBot"
},
"channelConversationId": "ConvId"
}
where "ConvId" is the id given by my local emulator in the original message (Note, that I have to send channelConversationId not conversationId).
Obviously, this is not enough for the live bot connector site. But what is a (minimum) example for replying to a message with the REST API call /bot/v1.0/messages?
I've tested different payload data, for example with attributes from, to, channelConversationId, textand language as indicated in the docs. But usually I get a 500 error:
{
"error": {
"message": "Expression evaluation failed. Object reference not set to an instance of an object.",
"code": "ServiceError"
}
}
When I tried to send back the original message, just with to and from swapped, I got a different 500 error:
{
"error": {
"code": "ServiceError",
"message": "*Sorry, Web Chat is having a problem responding right now.*",
"statusCode": 500
}
}
The minimum payload for an inline reply (returned as the response) is:
{ "text": "Hello, Hello!" }
If you're posting a reply to out of band using a POST to /bot/v1.0/messages then you're correct you need a little more. Here's what I do in the Node version of the Bot Builder SDK:
// Post an additional reply
reply.from = ses.message.to;
reply.to = ses.message.replyTo ? ses.message.replyTo : ses.message.from;
reply.replyToMessageId = ses.message.id;
reply.conversationId = ses.message.conversationId;
reply.channelConversationId = ses.message.channelConversationId;
reply.channelMessageId = ses.message.channelMessageId;
reply.participants = ses.message.participants;
reply.totalParticipants = ses.message.totalParticipants;
this.emit('reply', reply);
post(this.options, '/bot/v1.0/messages', reply, (err) => {
if (err) {
this.emit('error', err);
}
});
Sending a reply to an existing conversation is a little complicated because you have to include all of the routing bits needed to get it back to the source conversation. Starting a new conversation is significantly easier:
// Start a new conversation
reply.from = ses.message.from;
reply.to = ses.message.to;
this.emit('send', reply);
post(this.options, '/bot/v1.0/messages', reply, (err) => {
if (err) {
this.emit('error', err);
}
});
Both examples assume that reply.text & reply.language has already been set.
Meanwhile, the answer has been posted to a GitHub issue, quoting wiltodelta
Experimentally found necessary parameters for Slack, Skype, Telegram: ... ChannelConversationId only necessary Slack, otherwise the message will be added #userAddress.
Message message = new Message
{
ChannelConversationId = channelConversationId,
From = new ChannelAccount
{
ChannelId = channelId,
Address = botAddress,
IsBot = true
},
To = new ChannelAccount
{
ChannelId = channelId,
Address = userAddress
},
Text = text
};
Especially, the attributes replyToMessageId and channelConversationId (earlier mentioned) are not necessary: They refer to the last seen message in the conversation and thus will change during a conversation.

Calling a python function using dojo/request

Firstly, I'm very new to the world of web development, so sorry if this question is overly simple. I'm trying to use python to handle AJAX requests. From reading the documentation it seems as though Dojo/request should be able to do this form me, however I've not found any examples to help get this working.
Assuming I've got a Python file (myFuncs.py) with some functions that return JSON data that I want to get from the server. For this call I'm interested in a particular function inside this file:
def sayhello():
return simplejson.dumps({'message':'Hello from python world'})
What is not clear to me is how to call this function using Dojo/request. The documentation suggests something like this:
require(["dojo/dom", "dojo/request", "dojo/json", "dojo/domReady!"],
function(dom, request, JSON){
// Results will be displayed in resultDiv
var resultDiv = dom.byId("resultDiv");
// Request the JSON data from the server
request.get("../myFuncs.py", {
// Parse data from JSON to a JavaScript object
handleAs: "json"
}).then(function(data){
// Display the data sent from the server
resultDiv.innerHTML = data.message
},
function(error){
// Display the error returned
resultDiv.innerHTML = error;
});
}
);
Is this even close to what I'm trying to achieve? I don't understand how to specify which function to call inside myFuncs.py?
What you could also do is to create a small jsonrpc server and use dojo to do a ajax call to that server and get the json data....
for python side you can follow this
jsonrpclib
for dojo you could try something like this..
<script>
require(['dojox/rpc/Service','dojox/rpc/JsonRPC'],
function(Service,JsonRpc)
{
function refreshContent(){
var methodParams = {
envelope: "JSON-RPC-2.0",
transport: "POST",
target: "/jsonrpc",
contentType: "application/json-rpc",
services:{}
};
methodParams.services['myfunction'] = { parameters: [] };
service = new Service(methodParams);
function getjson(){
dojo.xhrGet({
url: "/jsonrpc",
load : function(){
var data_list = [];
service.myfunction().then(
function(data){
dojo.forEach(data, function(dat){
data_list.push(dat);
});
console.log(data_list)
},
function(error) {
console.log(error);
}
);
}
});
}
getjson();
}
refreshContent();
});
});
</script>
I've used this approach with django where i am not creating a different server for the rpc calls but using django's url link to forward the call to my function.. But you can always create a small rpc server to do the same..

Decoding JSON with python using Appengine

I have the following code which retrieves values from a simple 3 input form:
//retrieves data from a form
var $form = $( this ),
prgname= $form.find('input[name="prg"]').val(),
startDate = $("#startdate").datepicker({ dateFormat: 'yy-mm-dd' }).val(),
endDate = $("#enddate").datepicker({ dateFormat: 'yy-mm-dd' }).val();
The following code sends the request to the server:
var request = $.ajax({
url: "/prg/",
type: "post",
data: JSON.stringify({prg: prgname, start:startDate, end:endDate}),
contentType: 'application/json',
dataType: 'json',
success: function() {},
error: function (jqXHR, textStatus, errorThrown){};
on the server end using python and webapp2 Im doing the following, (here is where I am unsure of things)
import json
class PrgHandler(webapp2.RequestHandler):
def post(self):
prg= cgi.escape(self.request.POST['prg'])
start_date = cgi.escape(self.request.POST['start'])
end_date = cgi.escape(self.request.POST['end'])
#some code to write to db here
....
#if successful return a success message
if success:
success_msg = [{'class': 'success', 'msg': 'Successfully saved to the database'}]
else:
success_msg = [{'class': 'error', 'msg': 'Could not saved to the database'}]
data_string = json.dumps(success_msg)
self.response.headers.add_header('content-type', 'application/json', charset='utf-8')
self.response.write(data_string)
When I get the response it is skipping the success function and going directly to the error.
Logging the error values im not getting any thing meaningful:
the error is:
The text status is:error
The jqXHR is:[object Object]
Chrome's console is giving me the error:
Resource interpreted as Document but transferred with MIME type application/json:
I looked that up and the solutions on SO did not work, I think this is an error with the server side code:
self.response.headers.add_header('content-type', 'application/json', charset='utf-8')
If I comment out the above line I get no error in chrome and I just get back the response on a blank page with the correct values in the following format:
[{"msg": "Successfully saved to the database", "class": "success"}]
In the above case it does save to the database so I cannot seem to find anything wrong except for the header and simply don't know how to proceed!
EDIT
The error it seems is from the server side I had removed the following line:
event.preventDefault();
from my script and it caused all the problems now at least Im getting a clear indication of where the problem is. It's from incorrectly getting the posted data, how would I do it the correct way? I tried the following:
json_data = self.request.GET.items()
decoded = json.loads(json_data)
but Im getting a TypeError: expected string or buffer on the following line:
json_data = self.request.GET.items()
Have a look in your debugger. You receive a JSON string in your post (webapp2 multidict). You have to decode this string using json.loads, resulting in a python object.
Here is my jquery code to send and receive json :
function gaeQuery(request) {
var url = "/query";
var payload = {'jsondata' : JSON.stringify(request)};
$.post(
url,
payload,
function(response) {
procesResponse(response);
}, // succes response callback
'json', // response contains JSON content, and will be decoded in a js object
{
contentType: "application/json;charset=utf-8", // send JSON content
timeout: 20000,
tryCount: 0,
retryLimit: 3, // max 3 retries
error: function(xhr, textStatus, errorThrown) { // error handling callback
if (textStatus === 'timeout') {
this.tryCount++;
if (this.tryCount <= this.retryLimit) { //try again until retryLimit
$.ajax(this);
return;
}
alert('We have tried ' + this.retryLimit + ' times and it is still not working. We give in. Sorry.');
return;
}
if (xhr.status === 500) { // internal server error
alert('Oops! There seems to be a server problem, please try again later.');
}
else {
alert('Oops! There was a problem, sorry.'); // something went wrong
}
}
}
);
}
OK so I managed to figure this out and thought I will post the answer that worked for me to help anyone looking for this information because the webapp2 docs are not that helpful when it comes to 'getting' posted json data.
on the client side I did the following:
var request = $.ajax({
url: "/some/url/",
type: "POST",
data: JSON.stringify([{someval: val1, someval2:val2, someval3:val3}]),
contentType: "application/json",
dataType: 'json',
beforeSend: function() {
$('#loading-div').show();
},
complete: function(){
$('#loading-div').hide();
},
success: function(response, textStatus, jqXHR){}
});
The reason I couldnt figure out the problem straight away was because of the following line which I deleted along with some commented out line which prevented the page from redirecting after posting. This was the source of all the weird, unrelated and unhelpful error messages:
event.preventDefault();
on the server side to get the json data being posted to appengine do the following:
jdata = json.loads(cgi.escape(self.request.body))
for vals in jdata:
val1 = vals['someval']
val2 = vals['someval2']
val3 = vals['someval3']
The above was the root of the problem I wasn't doing it right and without the previous line on the client side there was no way to figure it out.
Anyways once you have the data do whatever processing you need to do with it and once you are done and need to send back a json response add the following lines:
//the data would look something like this
data = {'return_value': val1, 'return_value2': val2,
'return_value3': val3, 'return_value4': val4}
return_data = json.dumps(data)
self.response.headers.add_header('content-type', 'application/json', charset='utf-8')
self.response.write(return_data)
Almost forgot on the client side again to access the variables sent back from the server with jquery its very straight forward...do something like:
success: function(response, textStatus, jqXHR){
console.log(response.return_value);
console.log(response.return_value2);
console.log(response.return_value3);
}
Hope this will help someone seeking this information.

Categories