Uploading file to Spring REST server using Python Requests - python

I am trying to upload a file using python requests to my java/scala spring rest server. I am getting the following response:
{"timestamp":1454331913056,"status":400,"error":"Bad Request","exception":"org.springframework.web.bind.MissingServletRequestParameterException","message":"Required MultipartFile parameter 'image' is not present","path":"/parking_api/images"}
my server code:
#RequestMapping(value = Array("/parking_api/images"), method = Array(RequestMethod.POST)) def images(#RequestParam("image") image: MultipartFile) = {
if (image.isEmpty){
// handle empty
new ResponseEntity(response, HttpStatus.BAD_REQUEST
} else {
// process
new ResponseEntity(response, HttpStatus.OK)
}
}
My client code:
requests.post(parking_webservice_address, files={"image": ("image", open(event.pathname, "rb"), "image/jpeg")})
I have tried:
setting files parameter in python code to just {"image":open(...)} instead of tuple
passing image data loaded to memory using open(...).read() to files parameter in python code
setting CommonsMultipartResolver in server like this
#Bean(name="multipartResolver")
public CommonsMultipartResolver multipartResolver(){
return new CommonsMultipartResolver();
}
setting multipart headers manually, but then it server expects boundary which is missing as things get from bad to worse
None of these options have worked for me. What am I missing?

Related

Reading Query Params of Get request in python file

I have a web application in which a map is being displayed. Right now all the markers are being passed via one API (http:3000/example) created in a node/express server. My goal is to read the user location that is retrieved from the frontend and use that as part of the query params to respond with only a selection of markers for the map based on algorithm written in python.
Main.js (Frontend)
async function callAPIAndUpdateMap(queryParams) {
const api = `http://localhost:3000/example?lat=${userCurrentPosition.lat}&lng=${userCurrentPosition.lng}${queryParams}`;
const listExampleEndpoint = new URL(api);
const response = await fetch(listExampleEndpoint);
exampleList = await response.json();
//todo: check if we need to remove all markers and put the updated new ones
let markers = drawMarkers();
new markerClusterer.MarkerClusterer({
map,
markers,
});
}
The function is called with params if selected by the user further down in the main.js file
function confirmFilter() {
appliedFilters = unconfirmedFilters;
let queryParams = ``;
appliedFilters.forEach((element) => {
queryParams += `&${element}=true`;
});
callAPIAndUpdateMap(queryParams);
let filterWrapper = document.getElementById("filter-wrapper");
filterWrapper.classList.add("hidden");
let filterButton = document.getElementById("filter-button");
let resetFilterIcon = document.getElementById("reset-filter");
if (appliedFilters.length != 0) {
filterButton.classList.add("active-map-button");
resetFilterIcon.classList.remove("hidden");
resetFilterIcon.classList.add("active-icon");
} else {
filterButton.classList.remove("active-map-button");
resetFilterIcon.classList.add("hidden");
resetFilterIcon.classList.remove("active-icon");
}
}
I am honestly a bit lost on how to read this request from a python file and then respond with data back. I have though about two different methods but I am not sure either would work.
Flask
I read the API get request using flask and respond directly in the python file
Python file triggered from Node.js
I read the get request from the Python file and apply the Algorithm and print a JSON dump that is triggered from a Node File
Python file that I am working with at the moment
import sys
import json
import requests
url = "http://3000/example"
r = requests.get(url, params=location)
data = r.json()
resp = {
"Response": 200,
"Message": "hello from Python File",
"Data":data
}
print(json.dumps(resp))
# using system module in python to send to node js
sys.stdout.flush()

Uploading an image using the Python Etsy API

I am trying to upload an image to Etsy through the API. However, the example on their website is given in PHP which I don't know how to code. I only know how to work with Python. On their website it says:
Image uploads can be performed using a POST request with the Content-Type: multipart/form-dataheader, following RFC1867.
Their example which is in PHP
// You must define the constants OAUTH_CONSUMER_KEY and OAUTH_CONSUMER_SECRET
// You must also assign values to the variables $access_token, $access_token_secret,
// $listing_id and $filename, and $mimetype.
// Your image file is assumed to be in the same directory as this code.
$oauth = new OAuth(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET);
$oauth->enableDebug();
$oauth->setToken($access_token, $access_token_secret);
try {
$source_file = dirname(realpath(__FILE__)) ."/$filename";
$url = "https://openapi.etsy.com/v2/listings/".$listing_id."/images";
$params = array('#image' => '#'.$source_file.';type='.$mimetype);
$oauth->fetch($url, $params, OAUTH_HTTP_METHOD_POST);
$json = $oauth->getLastResponse();
print_r(json_decode($json, true));
} catch (OAuthException $e) {
// You may want to recover gracefully here...
print $oauth->getLastResponse()."\n";
print_r($oauth->debugInfo);
die($e->getMessage());
}
In API doc it says
HTTP Method = POST
URI = /listings/:listing_id/images
This is what I have so far in Python:
client_secret=client_secret,resource_owner_key=resource_owner_key,resource_owner_secret=resource_owner_secret)
url = 'https://openapi.etsy.com/v2/listings'
payload = {'listing_id':'2343432434', 'images': :('test1.jpg', open('test1.jpg', 'rb'), 'image/jpeg')}
result = etsy.post(uri, params=payload)
When I run this code I get an 403 error. How can I fix my code so that it functions correctly? I have looked at other examples and just can't seem to make it work.

Connecting Python Backend to Android APP

How to use python as a backend for an Android App that is built using C#? The Python Backend is written using the Flask framework. The Android app is built using xamarin.
No matter what type of technology your server or the client use if they can communicate with each other using some sort of standard "protocol".
There are many ways to communicate both sides (client and server) like sockets, xml, json, etc. They just need to understand each other.
In your particular case I suggest to build a REST or RESTful API (https://flask-restful.readthedocs.org/en/0.3.3/) on the server and a REST client library on the client.
There are many ways and libraries to call REST APIs from C#:
The built-in method would be using HttpWebRequest as you can see on this link:
private async Task<JsonValue> FetchWeatherAsync (string url)
{
// Create an HTTP web request using the URL:
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create (new Uri (url));
request.ContentType = "application/json";
request.Method = "GET";
// Send the request to the server and wait for the response:
using (WebResponse response = await request.GetResponseAsync ())
{
// Get a stream representation of the HTTP web response:
using (Stream stream = response.GetResponseStream ())
{
// Use this stream to build a JSON document object:
JsonValue jsonDoc = await Task.Run (() => JsonObject.Load (stream));
Console.Out.WriteLine("Response: {0}", jsonDoc.ToString ());
// Return the JSON document:
return jsonDoc;
}
}
}
But I don´t recommend it if you don´t want your app to be full of crap (boiler plate code) everywhere.
A helper library could be, for example, RESTSharp. It allows you to build REST calls easily and cast the response to your typed objects. Here´s and example:
var client = new RestClient("http://example.com");
// client.Authenticator = new HttpBasicAuthenticator(username, password);
var request = new RestRequest("resource/{id}", Method.POST);
request.AddParameter("name", "value"); // adds to POST or URL querystring based on Method
request.AddUrlSegment("id", "123"); // replaces matching token in request.Resource
// easily add HTTP Headers
request.AddHeader("header", "value");
// add files to upload (works with compatible verbs)
request.AddFile(path);
// execute the request
RestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
// or automatically deserialize result
// return content type is sniffed but can be explicitly set via RestClient.AddHandler();
RestResponse<Person> response2 = client.Execute<Person>(request);
var name = response2.Data.Name;
// easy async support
client.ExecuteAsync(request, response => {
Console.WriteLine(response.Content);
});
// async with deserialization
var asyncHandle = client.ExecuteAsync<Person>(request, response => {
Console.WriteLine(response.Data.Name);
});
// abort the request on demand
asyncHandle.Abort();
You can search "C# REST client" on google and judge by yourself. But IMHO, the easier and nicer to code REST client I´ve ever used is Refit.
Why? you define API calls and responses with just an interface. No coding required at all! Even more, all your API calls will be async by default, something needed for mobile apps to be responsive. From the author´s readme:
public interface IGitHubApi
{
[Get("/users/{user}")]
Task<User> GetUser(string user);
}
var gitHubApi = RestService.For<IGitHubApi>("https://api.github.com");
var octocat = await gitHubApi.GetUser("octocat");
I´ve used this library on Xamarin Android/iOS projects and it works well. No issues at all.
Hope it helps

Upload an image from iphone to GAE blobstore

I spent all this morning looking for a clear example on how to upload a picture taken with an iPhone to the blobstore, but without succeed.
Currently I have my iPhone app developed, which can send pics to the server in PHP, with this code in the server:
// Function to upload a photo in a file and save data in the DB
function upload($photoData, $descr, $phone) {
// Folder to upload data
$path = $_SERVER['DOCUMENT_ROOT']."/program/data/";
// Check if there was no error during the file upload
if ($photoData['error'] == 0) {
$result = query("INSERT INTO pics(descr, phone) VALUES('%s','%s')", $descr, $phone);
if (!$result['error']) {
// Inserted in the database, go on with file storage
// Obtain database link (in lib.php)
global $link;
// Get the last automatically generated ID
$idPhoto = mysqli_insert_id($link);
// Move the temporarily stored file to a convenient location
if (move_uploaded_file($photoData['tmp_name'], $path.$idPhoto.".jpg")) {
// File moved, all good, generate thumbnail
thumb($path.$idPhoto.".jpg", 180);
print json_encode(array('successful' => 1));
} else {
errorJson('Upload on server problem');
}
} else {
errorJson('Save database problem: '.$result['error']);
}
} else {
errorJson('Upload malfunction.');
}
}
The part in Objective-C that makes this works is (I'm using AFNetworking and the object API sharedInstance is an AFJSONRequestOperation class):
// Upload the image and the description to the web service
[[API sharedInstance] commandWithParams:[NSMutableDictionary dictionaryWithObjectsAndKeys:
#"upload", #"command",
UIImageJPEGRepresentation(originalPhoto, 70), #"file",
description, #"descr",
phoneNumber, #"phone",
nil]
onCompletion:^(NSDictionary *json) {
// Finished and response from server
if (![json objectForKey:#"error"]) {
// Success
[[[UIAlertView alloc]initWithTitle:#"Info"
message:#"Thanks"
delegate:nil
cancelButtonTitle:#"Dismiss"
otherButtonTitles: nil] show];
// Send a notification so the main view can reload the data
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateStream" object:nil];
} else {
// Error
NSString* errorMsg = [json objectForKey:#"error"];
[UIAlertView error:errorMsg];
}
}];
This works fine and the images are saved on the server. But I want to make the same with datastore, which you can't save files. So I made a webpage to practice on save images, and I can upload images without any problem in the blobstore from an standard web form. This is the code I'm using to save it in GAE (forget about my own helper classes or functions like PicturePageHandler or render_page):
# Get and post for the create page
class Create(PicturePageHandler, blobstore_handlers.BlobstoreUploadHandler):
def get(self):
if self.user_logged_in():
# The session for upload a file must be new every reload page
uploadUrl = blobstore.create_upload_url('/addPic')
self.render_page("addPicture.htm", form_action=uploadUrl)
def post(self):
if self.user_logged_in():
# Create a dictionary with the values, we will need in case of error
templateValues = self.template_from_request()
# Test if all data form is valid
testErrors = check_fields(self)
if testErrors[0]:
# No errors, save the object
try:
# Get the file and upload it
uploadFiles = self.get_uploads('picture')
# Get the key returned from blobstore, for the first element
blobInfo = uploadFiles[0]
# Add the key and the permanent url to the template
templateValues['blobKey'] = blobInfo.key()
templateValues['servingUrl'] = images.get_serving_url(blobInfo.key(), size=None)
# Save all
pic = Picture.save(self.user.key, **templateValues)
if pic is None:
logging.error('Picture save error.')
self.redirect("/myPics")
except:
self.render_page("customMessage.htm", custom_msg=_("Problems while uploading the picture."))
else:
# Errors, render the page again, with the values, and showing the errors
templateValues = custom.prepare_errors(templateValues, testErrors[1])
# The session for upload a file must be new every reload page
templateValues['form_action'] = blobstore.create_upload_url('/addPic')
self.render_page("addPicture.htm", **templateValues)
My questions are:
Can I still using my Objective-C JSON call to upload a picture to the server or must I completely change the way to upload the picture?
How can I change the Python server code to get the picture from the JSON, if it is possible?
It's not exactly what you're after, but this might help:
http://brunofuster.wordpress.com/2011/03/11/uploading-an-image-from-iphone-to-appengine-blobstore-using-vraptor/

Send an image file using sockets , Android to Python

Im trying to send an image from an android client to a python server , I have achieved it before with a python test client and the server. Basically my client app takes a form consisting of users details and an image. Once the user selects the image I get the uri in the onActivityResult method and parse it to a string Like so
selectedImagePath = selectedImageUri.toString();
when the user hits submit button on the form the sending activity is invoked with the form data as extras in an array in a bundle like so.
Bundle b=new Bundle();
b.putStringArray("regValues", new String[]{name,email,selectedImagePath});
in the sending activity I establish a connection with the server and attempt to send the image like so .
`
//establish link with the server
try{
//refer to the host computer's loopback interface
host = InetAddress.getByName("10.0.2.2");
link = new Socket(host,port);
in = new BufferedReader(new InputStreamReader(link.getInputStream()));
//access the strings that were passed to this activity
Bundle b = this.getIntent().getExtras();
String[] regFormValues = b.getStringArray("regValues");
//display connection confirmation
String message = in.readLine();
status.setText(message);
File myFile = new File (regFormValues[2]);
byte [] mybytearray = new byte [(int)myFile.length()];
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(mybytearray,0,mybytearray.length);
OutputStream os = link.getOutputStream();
os.write(mybytearray,0,mybytearray.length);
os.flush();
link.close();
}
catch(IOException e ){
e.printStackTrace();
}
`
It connects to the server no problem , the
server creates a file for output to write the data to as usual but it just appears empty so no data is being recieved. I think it may be a problem with the file path on the client side. Any Ideas ?
EDIT: Basically I would like to know if I am accessing the image file in the right way or if you have any better suggestions for accessing and sending it.
Consider using methods such as File.exists() and File.isFile() to validate if the path is OK and whether the image is really there
Also check if the image even hits the wire - using tcpdump ro wireshark
I have solved it , as I use selectedImageUri = Uri.fromFile(photo); to get the uri if its taken by the camera and selectedImageUri = data.getData(); if its been selected by the file browser. I used selectedImagePath = selectedImagePath.substring(7); to strip the file:// form the camera's image path, resulting in a /sdcard/etc or wherever it stored it. To get the file path for the image chosen by the file browser i used this
// convert the image URI to the direct file system path of the image file
public String getRealPathFromURI(Uri contentUri) {
// can post image
String [] proj={MediaStore.Images.Media.DATA};
Cursor cursor = managedQuery( contentUri,
proj, // Which columns to return
null, // WHERE clause; which rows to return (all rows)
null, // WHERE clause selection arguments (none)
null); // Order-by clause (ascending by name)
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
Now it works as expected.

Categories

Resources