I've searched around here as well as elsewhere online and can't seem to find the answer for what I think is a simple error on my part. Basically I want to transfer a file from one machine to another by issuing a Python requests.POST request to a Java REST interface on the remote machine. The Java side looks like this:
#ApiOperation(value = "Binary file transfer", nickname = "Binary file transfer")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success", response = HttpMessageInformationReturnDataBean.class),
#ApiResponse(code = 404, message = "Not Found")})
#RequestMapping(value = "/vm/{version}/uploadbinfile", method = RequestMethod.POST)
public String handleFileUpload(#RequestParam("binaryFile") MultipartFile file) {
if (!file.isEmpty())
{
try
{ ... the code that handles the transfer
On the Python side, the method looks like this:
def xfer_trm_binaries(self):
params = {"file": ('binaryFile',os.path.basename('TRMServer.jar')),
"folder": os.path.dirname(self.dest_temp_path),
"submit": "Submit"}
url = self.form_url("/vm/v1/uploadbinfile", self.trm_server_ip_address, self.vrm_server_port)
header=self.form_header(self.vrm_key)
header['Content-Type'] = 'multipart/file-data; boundary=randomboundarysequence'
header['enctype'] = "multipart/file-data"
print 'Send :' + url
binfile = self.local_jar_path+'TRMServer.jar'
with open(binfile, 'rb') as mfile:
try:
result = requests.post(url, headers=header,
data=params, files={'file': mfile}, verify=False)
except Exception:
The header that gets assembled there looks like this:
{'Content-Type': 'multipart/file-data; boundary=randomboundarysequence', 'Accept': 'application/json', 'Authorization': u'Bearer 8b2b6e53-9008-44b7-9d34-b5ecb9659250', 'enctype': 'multipart/file-data'}
The request is sent, however the response is always a 400 error, because it complains the MultipartFile parameter 'binaryFile' is missing:
'{"timestamp":1488597880207,"status":400,"error":"Bad Request","exception":"org.springframework.web.bind.MissingServletRequestParameterException","message":"Required MultipartFile parameter \\'binaryFile\\' is not present","path":"/vm/v1/uploadbinfile"}'
I've tried adding a 'name' value to both the params and headers of the request but it always comes back with the 400 code. Does anyone out there know what I might be doing wrong?
Actually I eventually figured this out - basically I had a method that formed the header to include the oauth bearer token, along with the ContentType and AcceptType...I then overwrote those with the multipart file info. THAT was what the receiving REST interface didn't like. When I just eliminated those header attributes altogether, it seemed to figure it out on its own.
Related
We try using swagger 2.0 (OAS3) for the documentation of a Restful API, implemented in Java and based on Apache CXF (jaxrs).
For a handful API-Calls yet implemented, the documentation with swagger works fine, but the following Post-Request makes me struggling:
#POST
#Path("/documents")
#Consumes("multipart/mixed")
Response createDocument(
#RequestBody(description = "RestDocumentParams (required), InputStream and RelationshipParams",
content = { #Content(mediaType = "multipart/mixed", schema = #Schema(implementation = RestDocumentParams.class)),
#Content(mediaType = "application/octet-stream", schema = #Schema(type = "string", format = "binary")),
#Content(mediaType = "application/json", schema = #Schema(implementation = RelationshipParams.class)) })
#Multipart(value = "doc", type = MediaType.APPLICATION_JSON)
RestDocumentParams documentParams,
#Multipart(value = "file", type = MediaType.APPLICATION_OCTET_STREAM, required = false)
InputStream inputStream,
#Multipart(value = "rela", type = MediaType.APPLICATION_JSON, required = false)
RelationshipParams relationshipParams)
This method should create a new Document using at least the data given in RestDocumentParams. Optionaly a file object (InputStream) and additional
MetaData (RelationshipParams) can be provided. All this payload has to be provided in the RequestBody.
Using this method in a testframework (e.g. restassured) works fine.
My problem is, how I have to annotate this method correct with swagger-annotation, to use it in Swagger-UI.
Using the RequestBody-Annotation like above, seems not being the right way!
In Swagger-UI appears a combo-box within the description of the RequestBody and let me choose the three different media types.
But if I want to try out this method and edited one of the input parameters (e.g. entering a file name) and choose the next media type, the last editing is lost.
Comparing the json-Strukture of the requestBody for this method with the OAS3 definition for "multipart content" differ.
Regarding to the OAS3 definition, the requestBody should have look like this:
requestBody:
description: 'RestDocumentParams (required), InputStream and RelationshipParams'
content:
multipart/form-data:
schema:
properties:
docParams:
$ref: '#/components/schemas/RestDocumentParams'
relaParams:
$ref: '#/components/schemas/RelationshipParams'
fileName:
type: string
format: binary
But I don't know how I have to specify the requestBody (using swagger annotoations) to achive a structure which looks like this.
please, this is y concern: I'll like to know how to query a web service defined as in the below code using postman for test purposes.
PS: I can't change the method signature
I have a web service like this :
#POST
#Path("/uploadOpenAccountRequestFiles/{requestId}")
#Consumes({MediaType.APPLICATION_JSON,MediaType.MULTIPART_FORM_DATA})
public Response uploadOpenAccountRequestFiles(#PathParam("requestId") String requestId,
MultipartFormDataInput multipartFormDataInput)
throws JsonGenerationException, JsonMappingException, IOException {
initContext();
logger.info("DIGIBANK : uploadOpenAccountRequestFiles END: ");
String msge = "";
try {
digiBean.saveToserver(requestId, multipartFormDataInput);
} catch (Exception e) {
msge = e.getMessage();
e.printStackTrace();
}
org.af.webservice.Response resp = new org.af.webservice.Response(
request.getSession().getId(), "uploadOpenAccountRequestFiles", "",
msge.equalsIgnoreCase("OK") ? true : false, msge.equalsIgnoreCase("OK") ? false : true, "",
msge.equalsIgnoreCase("OK") ? true : false, "Boolean", msge);
logger.info("DIGIBANK : uploadOpenAccountRequestFiles END: ");
return Response.ok().entity(mapper.writeValueAsString(resp)).build();
}
this is are images of my configurations:
enter image description here
enter image description here
For calling that service, you need to pass requestId like below:
http://localhost:8080/uploadOpenAccountRequestFiles/requestId-value-here
For sending MultiPart data such as a file, you need to select form-data option in the body section in Postman and select the file by selecting the File dropdown. Also, make sure to set the appropriate headers for the request.
Check the below stackoverflow answer for more details:
Tool for sending multipart/form-data request
The steps of uploading a file through postman along with passing some input data along with the multipart request is very well discussed in below blog along with the screenshot. In this blog, the api code is written in node js. You can go through it once. It may give some information.
https://jksnu.blogspot.com/2021/09/how-to-create-post-request-with.html
I need to send a video file and JSON object in Rest Assured post call.
Structure is like the following:
{ "sample" : {
"name" : "sample-name",
"kind" : "upload",
"video_file" : multipart file here } }
So I did like the following
Code:
given()
.header("Accept", "application/json")
.header(auth)
.config(rConfig)
.body(body)
.multiPart("sample[video_file]", new File("path"), "video/mp4")
.formParam("sample[name]", "Video Upload")
.formParam("sample[kind]", "upload")
.log().all().
expect()
.statusCode(expectedStatusCode)
.post(url);
I can't use application/JSON while using multipart in Rest Assured. I explicitly hardcoded the value in the form param and sent the media file in multipart and now it is working fine.
How can I send all the form param data in a single inner object.
You can do this by using RequestSpecBuilder. It supports all the request parameters and you can easily create multipart request.
Sample code taken from https://github.com/rest-assured/rest-assured/wiki/Usage
RequestSpecBuilder builder = new RequestSpecBuilder();
builder.addParam("parameter1", "parameterValue");
builder.addHeader("header1", "headerValue");
RequestSpecification requestSpec = builder.build();
given().
spec(requestSpec).
param("parameter2", "paramValue").
when().
get("/something").
then().
body("x.y.z", equalTo("something"));
Thanks for your response rohit. I was post this question for handling inner object with formParams. I've completed by creating a Hash Map for formParams. Because formParams method of rest assured can accept Hash map.
Form params map creation:
private static Map<String, String> createFormParamsMap(VideoTagInput videoTag) {
Map<String, String> formParams = new HashMap<>();
formParams.put(createFormParamKey("name"), "name");
formParams.put(createFormParamKey("kind"), "kind");
return formParams;
}
private static String createFormParamKey(String paramKey) {
return "sample[" + paramKey + "]";
// output is like "sample[name]" - I'm forming inner object here for my purpose.
}
Finally send the map to Rest Assured post call function
given()
.header("Accept", "application/json")
.header(auth)
.config(rConfig)
.multiPart("sample[video_file]", new File("path"), "video/mp4")
.formParams(requestParamsMap) // requestParamsMap here.
.log().all().
expect()
.statusCode(expectedStatusCode)
.post(url);
Your approach is definitely not standard.
You cannot have a multipart request and a JSON body, you need to pick one over the 2 approaches: multipart/form-data or application/json request.
The standard way is to have a multipart request with a "json" param containing the serialized JSON payload, and a "file" param with the multipart file.
given()
.contentType(MediaType.MULTIPART_FORM_DATA_VALUE)
.multiPart(file)
.param("json", "{\"sample\":{\"name\":\"sample- name\",\"kind\":\"upload\",\"video_file\":<this is not needed>}}")
But this involves changing your server-side logic.
If you cannot change your server-side logic, you need to serialize your file as (for instance as an array of bytes, or as base64 string) to be set as video_file in your JSON payload. In which case you'll have an application/json content type request, not a 'multipart/form-data'.
I want to send the data to person object. How to do it with PostMethod.
def payload ='<person><nationalId>'+1234567+'</nationalId></person>'
def method = new PostMethod(url)
def client = new HttpClient()
payload = payload.trim()
method.addRequestHeader("Content-Type","text/xml")
method.addRequestHeader("Accept","text/xml,application/xml;q=0.9")
Credentials credentials = new UsernamePasswordCredentials('simple', 'simple');
client.getState().setCredentials(new AuthScope(AuthScope.ANY_HOST,8080, AuthScope.ANY_REALM, "digest"),credentials);
method.setRequestEntity(new StringRequestEntity(payload))
def statusCode = client.executeMethod(method)
println "STATUS CODE : ${statusCode}"
def resultsString = method.getResponseBodyAsString()
method.releaseConnection()
println resultsString
I tried above coding. How to set password and username and password digest also. For that i think status code 400 is coming.Please notify where i made mistake
Try to look at REST Client Builder Plugin. See docs and I guess, you'll find more convenient way to send request
I have the already working javascript AJAX POST like this:
Client side:
<script language="JavaScript" type="text/javascript">
var column = "test1";
var filterType = 1;
var values = [];
var filter = { "column" : column, "filterType" : filterType, "values": values};
var filter2 = { "column" : column, "filterType" : filterType, "values": values};
filter2.column = "test2";
var filters = new Array();
filters[0] = filter;
filters[1] = filter2;
$.ajax({
url: "${pageContext.request.contextPath}/api/user_administration/get",
data: JSON.stringify(filters),
type: "POST",
beforeSend: function(xhr)
{
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Content-Type", "application/json");
},
success: function(user)
{
}
});
</script>
Server side:
#RequestMapping(value = "user_administration/get", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public List<User> get(#RequestBody ColumnFilter[] filters)
{
//do something
return userService.getAll();
}
Now I want to pass two or more parameters. Something like this:
#RequestMapping(value = "user_administration/get", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public List<User> get(#RequestBody ColumnFilter[] filters, #RequestBody ColumnSorter[] sorters)
{
//do something
return userService.getAll();
}
Is it possible to achieve this? How?
(I already am aware that I can just encapsulate them into another object/class/entity)
In your AJAX call you have the line
data: JSON.stringify(filters),
Change or extend this line to add additional parameters to the request. And if you're not clear what's going on or need to log/diagnose/debug it, you can always use an intermediate variable..
You can either pass data as a Javascript key-value object (giving named parameters), a String, or -- as the existing code does -- by JSON encoding an object.
Since you appear to want to pass more fields/parameters & are using JSON encoding already, it probably makes most sense to built these into a larger 'payload' object before JSON encoding.
var paramData = {filter:filters, sorters: mySortersOrWhatever};
console.log('some administration AJAX request', paramData);
$.ajax({
...
data: JSON.stringify(paramData)
See how this interfaces with Spring's request-parsing -- to decode two separate parameters on the Spring side you'll either need names (not just the request-body), decode them from named parameters, or else (simplest) just accept one big JSON object as the parameter.
This should be reasonably straight-forward -- as always, follow basic software-engineering principles (log it, diagnose it, fix it until it works) so you can build the required working functionality.
Spring documentation says:
The #RequestBody method parameter annotation indicates that a method
parameter should be bound to the value of the HTTP request body.
This assumes that HTTP request body is not divisible. Hence all you need to do is to follow the workaround.Here you can see exactly the same question Spring REST multiple #RequestBody parameters, possible?