Alamofire 5 multipart image upload issue swift for flask API - python

I was trying to upload single image via Alamofire 5 multipart data, API is working fine on Postman as well as on android side, but it is not working on iOS side.
API is developed in Python flask. Image is taken from camera and by using JPEGCompression uploading image.
Following is my code:
func postMultipartData(imageData: Data, completion:#escaping (Result<AccuracyModel?, ErrorResponse>) -> Void) {
let url = APIConstant.ImageAccuracyBaseUrl.BASEURL
let mimeType = "image/jpeg"
let headers: HTTPHeaders = [
"Content-Type": ContentType.multipart.rawValue
]
AF.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(imageData, withName: "file", fileName: "file123.jpg", mimeType: mimeType)
print(multipartFormData.boundary)
}, to: url, usingThreshold: UInt64.init(),
method: .post,
headers: headers).response { response in
switch response.result {
case .success(_):
if response.response?.statusCode == 200 || response.response?.statusCode == 201 {
do {
if let data = response.data {
let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
print(json ?? "")
let decodedData = try! JSONDecoder().decode(AccuracyModel.self, from: data)
DispatchQueue.main.async {
completion(.success(decodedData))
}
} else {
print(response)
}
} catch {
completion(Result.failure(self.generateErroModel()!))
}
} else if response.response?.statusCode == 500 {
completion(Result.failure(self.generateErroModel()!))
} else {
fallthrough
}
break
case .failure(_):
completion(Result.failure(self.generateErroModel()!))
}
}
}
For testing purpose api is using 5000 port, can that be issue?
There are no parameters required, so not sending any.
I have also tried by using NSURLSession, but no luck.
For Flask code, I have referred following link:
https://pytorch.org/tutorials/intermediate/flask_rest_api_tutorial.html
Thanks in Advance.

Related

Swift HTTP session not sending actual Request

So I have some Swift code that send a request to my local host
//
// ContentView.swift
// Shared
//
// Created by Ulto4 on 10/23/21.
//
import SwiftUI
struct ContentView: View {
var body: some View {
VStack{
Text("Hello, world!")
.padding()
Button(action : {
self.fu()
}, label: {
Image(systemName: "pencil").resizable().aspectRatio(contentMode:.fit)
})
}
}
func fu(){
let url = URL(string: "http://127.0.0.1:5000/232")
guard let requestUrl = url else { fatalError() }
var request = URLRequest(url: requestUrl)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
print("Error took place \(error)")
return
}
if let response = response as? HTTPURLResponse {
print("Response HTTP Status code: \(response.statusCode)")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
}
However, on my Flask app there are no get requests coming in and the function isn't running. There also isn't anything printing to the console.
I am fairly new to swift so I don't really know how to fix this.
Is there any other way to send requests in swift, if not, How would I fix this?
You are creating the URLSessionDataTask, but you never start it. Call task.resume(), e.g.
func performRequest() {
guard let url = URL(string: "http://127.0.0.1:5000/232") else {
fatalError()
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
print("Error took place \(error)")
return
}
if let response = response as? HTTPURLResponse {
print("Response HTTP Status code: \(response.statusCode)")
}
}
task.resume() // you must call this to start the task
}
That having been said, a few caveats:
You are doing http rather than https. Make sure to temporarily enable insecure network requests with app transport settings, e.g.
You didn’t say if this was for macOS or iOS.
If running on physical iOS device, it will not find your macOS web server at 127.0.0.1 (i.e., it will not find a web server running on your iPhone). You will want to specify the IP number for your web server on your LAN.
If macOS, make sure to enable outbound network requests in the target’s “capabilities”:
You asked:
Is there any other way to send requests in swift?
It is probably beyond the scope of your question, but longer term, when using SwiftUI, you might consider using Combine, e.g., dataTaskPublisher. When running a simple “what was the status code” routine, the difference is immaterial, but when you get into more complicated scenarios where you have to parse and process the responses, Combine is more consistent with SwiftUI’s declarative patterns.
Let us consider a more complicated example where you need to parse JSON responses. For illustrative purposes, below I am testing with httpbin.org, which echos whatever parameters you send. And I illustrate the use of dataTaskPublisher and how it can be used with functional chaining patterns to get out of the mess of hairy imperative code:
struct SampleObject: Decodable {
let value: String
}
struct HttpBinResponse<T: Decodable>: Decodable {
let args: T
}
class RequestService: ObservableObject {
var request: AnyCancellable?
let decoder = JSONDecoder()
#Published var status: String = "Not started yet"
func startRequest() {
request = createRequest().sink { completion in
print("completed")
} receiveValue: { [weak self] object in
self?.status = "Received " + object.value
}
}
func createRequest() -> AnyPublisher<SampleObject, Error>{
var components = URLComponents(string: "https://httpbin.org/get")
components?.queryItems = [URLQueryItem(name: "value", value: "foo")]
guard let url = components?.url else {
fatalError("Unable to build URL")
}
return URLSession.shared.dataTaskPublisher(for: url)
.map(\.data)
.decode(type: HttpBinResponse<SampleObject>.self, decoder: decoder)
.map(\.args)
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
}
struct ContentView: View {
#ObservedObject var requestService = RequestService()
var body: some View {
VStack{
Text("Hello, world!")
.padding()
Button {
requestService.startRequest()
} label: {
Image(systemName: "pencil").resizable().aspectRatio(contentMode:.fit)
}
Text(requestService.status)
}
}
}
But, like I said, it is beyond the scope of this question. You might want to make sure you get comfortable with SwiftUI and basic URLSession programming patterns (e.g., making sure you resume any tasks you create). Once you have that mastered, you can come back to Combine to write elegant networking code.
FWIW, like workingdog said, you could also use the new async-await rendition of data(for:delegate:). But when in the declarative world of SwiftUI, I would suggest Combine.

node request vs python session

I have a working node.js script which written using the node.js request module.
I'm trying to convert this script to python with the session module.
I'm new to python and I followed the python docs as it mentioned. but I'm struggling to get my code works.
the problem I'm having is sending the cookie values in the subsequent requests with the session module.
as per the docs it is saving cookies and send them automatically in any requests after that. but
here is my working node.js script
const request = require('request');
const fs = require('fs');
const getOptions = {
jar:true,
followAllRedirects:true,
method:'GET',
url:'https://dummyurl.com'
};
request.get(getOptions,(err,response,html)=>{
if(err){
console.log('error in request');
console.log(err);
}
else {
const postOptions = {
jar:true,
followAllRedirects: true,
method:'POST',
url:'https://dummyurl.com',
form:{
'data':{
'page':2
}
}
};
request.post(postOptions,(err,response,html)=>{
if(err){
console.log('post err');
console.log(err);
}
else {
fs.writeFileSync('pyres.html',html,'utf8');
}
})
}
});
this is my python conversion of above script
s = requests.Session()
url= 'https://dummyurl.com'
response = s.get(url)
print(response.cookies)
data_url = 'https://dummyurl.com/'
postData = {
"data":{
"page":2
}
}
resultResponse = s.post(data_url,data=postData)
print(resultResponse.content)
Can anyone points me out any mistake in this code?
actually the problem was in data format.
in nodejs I post it like this
{'data':{'page':2} }
but in python it should be converted like this
{
'data[page]': '2'
}
not sure why it was not worked in normal json format in python

How to send rest API (Google Vision's API) request with python?

I guess my question is relatively simple and naive, but I'm new to use REST APIs so I would be grateful for any help or hint.
I'm trying to send a request with urllib (or another Python's library that I no need to install).
Based on their guide, The format is:
POST https://vision.googleapis.com/v1/images:annotate?key=YOUR_API_KEY
and the JSON request format is:
{
"requests":[
{
"image":{
"content":"/9j/7QBEUGhvdG9...image contents...eYxxxzj/Coa6Bax//Z"
},
"features":[
{
"type":"LABEL_DETECTION",
"maxResults":1
}
]
}
]
}
When I try to send the following text (just for test) in the URL line in my browser:
https://vision.googleapis.com/v1/images:{
"requests":[
{
"image":{
"content":"/9j/7QBEUGhvdG9eYxxxzj/Coa6Bax//Z"
},
"features":[
{
"type":"LABEL_DETECTION",
"maxResults":1
}
]
}
]
}?key=my_api_key
I get unfortunately a 404 error.
What should I do? Should I use any library in order to generate the request? Or should I to place the JSON request in another place in the URL?
If you need to send Request Body with the URL you can use CURL. To test REST API's there is a famous software called POSTMAN. By using this you can send requests and receive the response.
CURL,
curl -v -H "Content-Type: application/json" -X POST \
-d '{"image":{"content":"/9j/7QBEUGhvdG9...image contents...eYxxxzj/Coa6Bax//Z"}, "features":[{"type":"LABEL_DETECTION","maxResults":1}]}' https://vision.googleapis.com/v1/images:annotate?key=YOUR_API_KEY
Using POSTMAN you can give these values to it and get results.
Give URL,
https://vision.googleapis.com/v1/images:annotate?key=YOUR_API_KEY
Choose HTTP METHOD as,
POST
And add the REQUEST BODY under the raw field and choose JSON(application/json),
{
"requests":[
{
"image":{
"content":"/9j/7QBEUGhvdG9...image contents...eYxxxzj/Coa6Bax//Z"
},
"features":[
{
"type":"LABEL_DETECTION",
"maxResults":1
}
]
}
]
}
This works for me:
import base64
import requests
import json
URL = "https://vision.googleapis.com/v1/images:annotate?key=YOUR_TOKEN"
#image to base64, which is a long long text
def encode_image(image_path):
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read())
#make api call
def image_request(image_path):
data = {
"requests":[
{
"image":{
"content":encode_image(image_path)
},
"features":[
{
"type":"LABEL_DETECTION", #other options: LABEL_DETECTION FACE_DETECTION LOGO_DETECTION CROP_HINTS WEB_DETECTION
"maxResults": 10
}
]
}
]
}
r = requests.post(URL, json = data)
return r.text
#arg = path of image
def main(argv):
api_answer = json.loads(image_request(argv[1]))
try:
rows = api_answer['responses'][0]['labelAnnotations']
except:
print(file_to_proccess)
print(api_answer)
data = []
for item in rows:
data.append([item['mid'], item['description'], item['score'], item['topicality']])
# save somewhere the data list...
if __name__ == "__main__":
main(sys.argv)
this was tested and work perfect
import base64
import requests
import json
url = "https://vision.googleapis.com/v1/images:annotate"
querystring = {"key":".........."}
headers = {
'Content-Type': "application/json",
}
def encode_image(image_path):
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read())
def image_request(image_path):
payload = '{ \"requests\":[ { \"image\":{ \"content\":\"'+encode_image(image_path).decode('utf-8')+'" }, \"features\":[ { \"type\":\"TEXT_DETECTION\" } ] } ]}'
response = requests.request("POST", url, data=payload, headers=headers, params=querystring)
return response.text

Node JS and Python - POST image from Node JS to Python REST API

I have a Node JS application. I want to send an image from the Node JS application to a REST API which is written in Python. The key and the inputs needed by the Python REST API are as follows
My problem is that I am able to POST a simple 'Hello World' string with the code I have written and get a response. However, when I try to send an image something goes wrong and I get no response.
var http = require('http');
var querystring = require('querystring');
// This is some dummy string data
var postData = querystring.stringify({
msg: 'hello world'
});
var fs = require('fs')
, path = require('path')
, certFile = path.resolve(__dirname, 'ssl/client.crt')
, keyFile = path.resolve(__dirname, 'ssl/client.key')
, caFile = path.resolve(__dirname, 'ssl/ca.cert.pem')
, request = require('request');
// I want to send an image from one server to another. What changes should I make to the options below for POSTing image data
var options = {
hostname: '127.0.0.1',
port: 8888,
path : '/predict',
//image: fs.createReadStream('car.jpg'), //Should I give something like this??
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
'Content-Length': postData.length
}
};
var req = http.request(options, function (res) {
console.log('STATUS:', res.statusCode);
console.log('HEADERS:', JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY:', chunk);
});
res.on('end', function () {
console.log('No more data in response.');
});
});
req.on('error', function (e) {
console.log('Problem with request:', e.message);
});
req.write(postData);
req.end();
Please let me know what changes I have to make to this code to post an image.I read about the use of multer package. However, the examples that I came across were using JS on both ends. Since for me, I have a Python REST API , I cannot use that. PLease help since I have been struggling with it for some time now.
Edit 1: Based on #Jana's suggestion, I added the multipart within the options and tried, where image is the key and the value is fs.createReadStream('car.jpg') . However, at the python end, it does not get the 'image' key because of which I get a False response. What am I missing?
var options = {
hostname: '127.0.0.1',
port: 8888,
path : '/predict',
//image: fs.createReadStream('car.jpg'), //Should I give something like this??
multipart: [
{
'content-type': 'application/json',
body: JSON.stringify({'image': fs.createReadStream('car.jpg') })
}
],
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
//'Content-Length': postImageData.length
}
};
Check this,
`request({
method: 'POST',
uri: 'http://127.0.0.1:8888/predict',
multipart: [{
'content-type': 'application/json',
body: JSON.stringify({
"key": "value"
})
},
{
body: fs.createReadStream('car.jpg')
}
],
},
function(error, response, body) {
if (error) {
return console.error('upload failed:', error);
}
console.log('Upload successful! Server responded with:', body);
})`
And also you can get the best examples from its own documentation Request - Simplified HTTP client

Server connection and read/write value

I want to read write value from a PLC through API (RESTful like) provide by constructor.
First step is authentification
Ajax code
$.ajax({
url: "http://192.168.10.11/sdcard/cpt/app/signin.php",
type: 'POST', dataType: 'json',data: {
'user[name]': 'admin',
'user[password]': 'hellocpt'
}
}).done(function(data) {
console.debug("signin done");
});
Next I can read value from JSON
var url='http://192.168.10.11/sdcard/cpt/app/data_api.php?
url=/app/objects/EasyIO/Ramp.out';
$.ajax(
{url: url, type: 'GET', dataType: 'json'}
).done(function(data) {console.debug(data);});
Response
{
"response" : {
"resultCode" : 0, // '0' for success, other numbers for
failure
"data" : [ // sedona object data is orgnized in list
{ // every object's data is a dictionary
"path" : "/EasyIO/Ramp", //sedona object's path
"slots" : [ //slots data is organized as a list
{
"value" : "49.000000", // 'out' slot's value
"slotType" : "property", // this slot is a
property
"name" : "out", // slot's name"type" : "float" // slot value's data type
}
]
}
]
}
}
Commande
var url = 'http://192.168.10.11/sdcard/cpt/app/data_api.php';
$.ajax({url: url,
type: 'POST',
dataType: 'json',
data: {
path: '/app/objects/EasyIO/WriteIn.in',
type: 'int',
value: '100',
slotType: 'property'
}
}).done(function(data) {
console.debug(data);
});
Response
{
"response" : {
"resultCode" : 0, // '0' for success, other numbers for
failure
"value" : "100", // slot value has been changed to '100'
"type" : "int", // slot data type is 'int'
"path" : "/app/objects/EasyIO/WriteIn.in" //slot's path
}
}
This API documentation
This my python3 code test
import os
import requests
import pycurl
import json
import urllib
from urllib.request import urlopen
headers = {
'X-Requested-With': 'XMLHttpRequest',
}
data = [
('user[name]', 'admin'),
('user[password]', 'hellocpt'),
]
response = requests.post('http://192.168.0.230/sdcard/cpt/app/signin.php', headers=headers, data=data)
print("Code Status du POST: ",response.status_code)
print(response.content)
cookies = {
}
params = (
('url', '/app/objects/EasyIO/Ramp.out'),
)
responseget = requests.get('http://192.168.0.230/sdcard/cpt/app/data_api.php', headers=headers, params=params, cookies=cookies)
print("\n\nCode Status du GET: ",responseget.status_code)
print(responseget.content)
and my output
Code Status du POST: 200
b'{"redirectUrl": "http://192.168.0.230/sdcard/cpt/dashboard/index.php" }'
Code Status du GET: 200
b'{"redirect": "http://192.168.0.230/sdcard/cpt/app/signin.php"}'
My problem is I don't understand why my POST command working but when I make a GET command I see redirection to signin page link. Why there is a logout?
Anyone can help?
Thanks
When you are sending your second request (GET), how will the server know that you have signed in before? The server sends you back something in the first request which you should send back to the server in your second request so the server can authenticate you.
I wasn't able to find out how your API is working using the ajax codes you have posted because the returned data is not shown in the first request but if we assume that the authentication is cookie based then instead of an empty cookie you should replace this line :
cookies = {
}
with this :
cookies = response.cookies
But this is only an example, your API might return a token instead of using cookies or some other type of authentication which is specified in the documentation.
EDIT : I was able to open the pdf file which contains the API documentation and it seems that the authentication is cookie based so the solution should work.

Categories

Resources