How to get Api access in Swift? - python

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)
}

Related

Is there a way to turn PIL string bytes into a viewable image on my web application?

I have marshalled PIL image into bytes via toBytes() on my Flask Server.
Then these bytes was then embedded in Json as a string and transferred via http to my Angular web application.
Is there a way to turn this binary into a viewable image on my web application? Or is there a better way transfering image from my Flask server to my Angular web application?
A part of my code python flask code:
imgByteArrTemp = io.BytesIO()
img.save(imgByteArrTemp, format="PNG")
# imgByteArrTemp = base64.b64encode(imgByteArrTemp.getvalue())
imgByteArrTemp = imgByteArrTemp.getvalue()
My GET method:
#app.route("/get-resulting-image", methods=["GET"])
def get_resulting_image():
global q
if not q.empty():
item = q.get()
return send_file(io.BytesIO(item),
mimetype = "image/png",
as_attachment=True,
download_name="%s.png")
return "no image to provide"
My typescript app.component.ts:
createImageFromBlob(image:Blob){
let reader = new FileReader();
reader.addEventListener("load", () => {
this.imageBinary = reader.result;
console.log(this.imageBinary);
},false);
if (image){
reader.readAsDataURL(image);
}
}
getResponse(){
...
this.restService.getCorrespondingImage().subscribe(
data1 => {
this.createImageFromBlob(data1);
this.isImageLoading = false;
},
error => {
this.isImageLoading = false;
console.log(error)
}
);
...
}
app.component.html
<img [src]="imageBinary" *ngIf="!isImageLoading">
rest.service.ts
import { Injectable } from '#angular/core';
import {HttpClient} from '#angular/common/http';
import {Observable, throwError} from 'rxjs';
import {catchError, retry} from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class RestService {
constructor(private http: HttpClient) { }
....
getCorrespondingImage():Observable<Blob>{
return this.http.get(
"http://192.168.1.2:9500/get-resulting-image",
{responseType:"blob"});
}
}
Hope this could help someone out there.

How do I get value from ValuesView? Trying to make sense of Dialogflow response for my bot

I'm trying to create a bot using DialogFlow, Twilio and Flask but I'm currently stuck at something that show seem easy but couldn't find a lot of answers.
Basically I fetch de json answer from Dialogflow using the function below:
def fetch_reply(query, session_id):
#gets response from DialogFlow
response = detect_intent_from_text(query, session_id)
resp = {}
#Understading response and seeting it to a dictionary
print(response)
resp['text']=response.fulfillment_text
resp['intent']=response.intent.display_name
resp['parameters'] = response.parameters.fields.values()
return resp
I printed the full response, and it gives me the following:
query_text: "Tim\303\243o"
parameters {
fields {
key: "soccerteams"
value {
string_value: "Corinthians"
}
}
}
all_required_params_present: true
fulfillment_messages {
text {
text: ""
}
}
intent {
name: "projects/whatsappbotsports-ylml/agent/intents/e7bcf0f5-d37f-4c8b-81ad-09579fded36a"
display_name: "Default Team Request"
}
intent_detection_confidence: 1.0
language_code: "pt-br"
but when I print the resp['parameter'] my result is:
ValuesView({'soccerteams': string_value: "Corinthians"
})
All I need to access is "Corinthians", or the value of string_value, but I can't find a way to do it. If I try to use resp['parameter'].value or resp['parameter'].string_value it gives me that ValuesView doesn't have this attributes.
Any idea how to do it?
That's some very strange output that you have. It's not a JSON, since the keys don't have quotes around them.
Can you try something like this?
import json
from google.protobuf.json_format import MessageToJson
def fetch_reply(query, session_id):
#gets response from DialogFlow
response = detect_intent_from_text(query, session_id)
# trying to parse json
soccerteams = response.parameters.fields["soccerteams"]
soccerteams_json = json.loads(MessageToJson(soccerteams))
return soccerteams_json
and then try to get the value from json.
That's just my try to adapt this code: Get Dialogflow context parameters from a follow up intent in Python
Let me know if it worked. If not, please send some output.

Flask-Login doesn't set cookies to browser with angular?

I'm building a fullstack web project using Angular 6 & Python Flask, mainly using Flask-Security extension.
Currently, I try to implement a login system of users, using the login_user() (Flask-Login's method). Basiclly, login_user() works, but I can't see any session cookies on my browser.
As documentation says, every change/new instance of session object sets/modifies cookies accordingly, so login_user() creates a new instance of session.
I'm running and testing the project on 'http://127.0.0.1:4200' (Angular default port), and Flask, using 'http://127.0.0.1:5000/'.
As a last resort, I tried to build a Flask app without any actual frontend, running and testing it from 'http://127.0.0.1:5000/', and it did work. I've managed to see the cookies that login_user() should've set from the start.
Mainly, my question, why doesn't it work with Angular?
frontend code:
export class Login {
constructor(private userSerivce : UserService, private router : Router) {}
outputMessage : string = null;
loginOnSubmit(form : FormGroup): void {
let formDict = {
"email" : form.controls["email"].value,
"password" : form.controls["password"].value
}
this.userSerivce.loginOnSubmit(formDict).subscribe({
next : value => {
//whatever, still didn't get here
},
error : response => {this.outputMessage = response.error}
})
}
backend login function:
#user_app.route('/signin', methods=['POST'])
def signIn():
session.permanent = True
status_code = 200
output_string = None
form = json.loads(request.data.decode('utf-8'))
user = User.query.filter_by(email=form['email']).first()
if user is not None:
if utils.verify_password(form['password'],user.password) and user.is_authenticated:
user.active = True
db.session.commit()
if login_user(user, True, datetime.timedelta(days=24), False, True):
i=1 #debugging purposes only
else:
status_code = 400
output_string = "error"
else:
status_code = 400
output_string = "error"
return jsonify(1), status_code
The models is exactly as documentation suggests, I even used the same code in my empty Flask app (the same classes and database, and as I said, it worked).
You can't set browser cookies by using the server session. You'd have to send cookies in the response. If you want to set cookies in the response, you could do something like this:
from flask import make_response # and your other stuff
# ... other imports ...
def login():
# ... some authentication code here to get your access_token (like a jwt)...
resp = make_response(redirect('http://localhost:4200')) # your angular app
resp.set_cookie('token', access_token) # set the cookie on the response header for the browser to extract
return resp # return the response with the new cookie attached
Since your client application isn't on the same domain as your server application, setting the session isn't going to help you in the way you want for authentication. The best way to do what you want is to pass a JWT back and forth between client and server.
One thing you can try to do (if you want to set some kind of authentication on the front end) would be to authenticate your user return a JWT back to Angular. You could then set an http header to come to the backend each time. The backend would parse the request and extract the JWT from the header. You would then use that header to authenticate the user's request to your backend by decrypting the JWT when it comes in. There is a great deal of literature on this. I'll put in some good tutorials at the end of this post.
You can use (in Angular) an HttpInterceptor. Something like this:
import { Injectable } from "#angular/core";
import { HttpInterceptor, HttpHandler, HttpEvent } from "#angular/common/http";
import { AuthService } from "../auth/auth.service";
import { HttpRequest } from '#angular/common/http';
import { Observable } from "rxjs";
#Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(public auth: AuthService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (this.auth.isLoggedIn()) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${this.auth.getToken()}`
}
});
}
return next.handle(request);
}
}
You could have an Auth service like so:
import { Injectable } from '#angular/core';
import { HttpClient, HttpParams, HttpHeaders } from '#angular/common/http';
import { CookieService } from 'ngx-cookie-service';
import { map } from 'rxjs/operators';
import { environment } from '../../environments/environment';
#Injectable({
providedIn: 'root'
})
export class AuthService {
redirectUrl: string;
// cookie service from ngx-cookie-service
constructor(private http: HttpClient, private cookieService: CookieService) { }
checkToken() {
return this.cookieService.check('token');
}
getToken() {
return this.cookieService.get('token');
}
loginWithUsernameAndPassword(userName: string, password: string) {
return this.http.post<any>(`${environment.API_URL}/auth/login`,
new HttpParams({fromObject: {userName, password}}),
{
headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
}
).pipe(map(user => {
if (user && user.token) {
this.cookieService.set('token', user.token);
}
return user;
}));
}
logout() {
this.cookieService.delete('token');
}
isLoggedIn() {
return this.cookieService.check('token');
}
registerWithUsernameAndPassword(userName, password, email) {
return this.http.post<any>(`${environment.API_URL}/auth/create`,
new HttpParams({fromObject: {userName, password, email}}),
{
headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
}
)
.pipe(map(user => {
console.log(user);
return user;
}));
}
}
In your AppModule you can then specify a provider called HTTP_INTERCEPTORS and use the HttpInterceptor you created -- in my case, I would call it TokenInterceptor:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing/app-routing.module';
import { SharedModule } from './shared/shared.module';
import { HttpClientModule, HTTP_INTERCEPTORS } from '#angular/common/http';
import { CookieService } from 'ngx-cookie-service';
import { AuthService } from './auth/auth.service';
import { TokenInterceptor } from './interceptors/token.interceptor';
#NgModule({
imports: [
BrowserModule,
AppRoutingModule,
SharedModule,
HttpClientModule
],
declarations: [
AppComponent,
],
exports: [],
providers: [
AuthService,
CookieService,
{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule {
}
A good reference for the interceptor: https://angular.io/api/common/http/HttpInterceptor
and: https://medium.com/#ryanchenkie_40935/angular-authentication-using-the-http-client-and-http-interceptors-2f9d1540eb8
And the canonical source on Flask would be Miguel Grinberg, who has written some JWT authentication tutorials -- https://blog.miguelgrinberg.com/post/json-web-tokens-with-public-key-signatures
here's another tutorial for JWT in Flask as well: https://realpython.com/token-based-authentication-with-flask/

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

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?

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..

Categories