I have a scenario where in my code creates a file and an event in cumulocity as well. I need to attach the binary file to the event, however none of the API's provide me the functionality, any guidance as to how to go ahead please?
Update:
On having a look at the documentation https://cumulocity.com/api/10.11.0/#tag/Attachments , the binaryElement has a following structure
I have modified my JAVA code in the following manner:
String pathEvent = platform.getUrl().get()+"/event/events/{{eventId}}/binaries";
String pathEventAttachment = pathEvent.replace("{{eventId}}", event.getId().getValue());
HttpHeaders headers = RequestAuthenticationEncoder.encode(getCredentials());
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("file",new ByteArrayResource(FileUtils.readFileToByteArray(file)));//anychanges here fails the code
map.add("filename", file.getName().getBytes());
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(map,headers);
restTemplate.postForObject(pathEventAttachment, request, String.class);
log.info("Binary file added to the event {}", event.getId().getValue());
Binary is created for the event, however the filename is incorrect:
Please let me know some insights as to why the name is not changing?
You need to create a POST on /event/events/{{eventId}}/binaries with the appropriate Content-Type and body.
Here is a code snippet in python where a binary (log file) is attached to an event. It just POSTs the file content (bytes) as application/octet-stream
# Create event
logfileEvent = {
'type': 'c8y_Logfile',
'text': 'See attached logfile',
'time': datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z',
'source': {
'id': DEVICE_ID
}
}
res = client.post(C8Y_BASE + '/event/events/', data=json.dumps(logfileEvent))
eventId = res.json()['id']
# Attach Binary
res = client.post(C8Y_BASE + '/event/events/' + eventId + '/binaries', data=bytes(FILE_CONTENT, 'utf-8'), headers={'Content-Type': 'application/octet-stream'})
binaryRef = res.json()['self']
# Update operation
logfileFragment = logfileOperation['c8y_LogfileRequest']
logfileFragment['file'] = binaryRef
updatedOperation = {
'status': 'SUCCESSFUL',
'c8y_LogfileRequest': logfileFragment
}
client.put(C8Y_BASE + '/devicecontrol/operations/' + logfileOperation['id'], data=json.dumps(updatedOperation))
Related
I have to call a DELETE Method inside one of the APIS of a client.
This shouldn´t be a problem but I am struggling with the framework that my company currently uses and I hope I can get some info that hopefully will help me solve the problem:
First thing first.
1: The api doesn´t work if I do the call sending the params as URL:
2: It works completely OK if I send the params inside the body as x-www-form-urlencoded but not form-data or raw
The documentation of the method inside the API told us the following: (Important to Look to IDEtapa)
I have to do this call in JAVA (JAVA 8)
currently my company uses HTTP_CLIENT as the main framework for APICalls.
My code:
The build of the Data (Currently I build both, as Entity and as Params for you to view I´ve tried with each one of them indepently):
Map datosApi = new HashMap<>();
datosApi.put(Constants.URL, anular_cita);
Map headers = new HashMap<>();
headers.put(Constants.AUTHORIZATION, params.get("token_autorizacion"));
headers.put("Content-Type", "application/json");
headers.put("entity_charset", "UTF-8");
datosApi.put(Constants.HEADERS, headers);
JSONObject entity = new JSONObject();
Map param = new HashMap();
param.put(Constants.ID_CENTRO, consul);
param.put("IdAsistencia", propiedades[0]);
param.put("IdCapitulo", propiedades[1]);
param.put("IdEtapa", Integer.valueOf(propiedades[2]));
entity.put(Constants.ID_CENTRO, consul);
entity.put("IdAsistencia", propiedades[0]);
entity.put("IdCapitulo", propiedades[1]);
entity.put("IdEtapa", Integer.valueOf(propiedades[2]));
datosApi.put("entity", entity.toString());
datosApi.put("entity_mime_type", "application/json");
datosApi.put("entity_charset", "UTF-8");
datosApi.put("params", param);
String anularCita = APIDao.callAPIDelete(datosApi);
The preparation for my call to the framework:
public static String callAPIDelete(Map in) {
String contentString = "";
Map res = new HashMap<>();
try {
res = XWM.execute("delete#http_client", in);
byte[] content = (byte[]) res.get("content");
contentString = new String(content, StandardCharsets.UTF_8);
And inside our framework we have this:
if (StringUtils.equals(StringUtils.trim(method), "delete"))
{
StringBuilder requestUrl = new StringBuilder(url);
if (formparams != null)
{
if (requestUrl.indexOf("?")==-1) requestUrl.append("?");
else requestUrl.append("&");
requestUrl.append(URLEncodedUtils.format(formparams, charset));
}
if (entityRequest != null)
{
log.error("Param 'entity' no puede usarse en get (se ignora)");
}
HttpDelete delete = new HttpDelete(requestUrl.toString());
delete.setConfig(requestConfig);
uriRequest = delete;
}
}
}
}
// Headers
if (headers != null)
{
for (String h: headers.keySet()) uriRequest.addHeader(h, headers.get(h));
}
// Ejecutamos método
log.info("Executing request " + uriRequest.getRequestLine());
CloseableHttpResponse response = null;
if (!preemtiveAuth || credsProvider == null)
{
response = httpclient.execute(uriRequest);
}
As you can see, in the delete method, we ignore the entity that i´ve built in the first patch of code.
The HTTPDelete Class is APACHE, the url with info of the class is the following:
https://www.javadoc.io/doc/org.apache.httpcomponents/httpclient/4.5.2/org/apache/http/client/methods/HttpDelete.html
The question can be divided in two:
1: Can we send the Entity in a Delete Call? I have found a few info about this in the following places:
Is an entity body allowed for an HTTP DELETE request?
https://web.archive.org/web/20090213142728/http://msdn.microsoft.com:80/en-us/library/cc716657.aspx
https://peterdaugaardrasmussen.com/2020/11/14/rest-should-you-use-a-body-for-your-http-delete-requests/
I assume that in order to do it, i would need a new HttpDelete that would allow us to use entity, if possible, could you give me some examples of this?
2: For what i understand of the links i posted above, while using entity in Delete calls is not forbidden is something that is not encouraged, Should I just talk with the people who made the API and ask them to change their configuration to allow us to send the info by params? (It is not personal or sensible info, just a bunch of IDs)
Thank you so much for your attention and my apologies for any typo or format mistake, still learning how to make good posts.
EDIT: i have found this answer setEntity in HttpDelete that more or less solve the first issue about if its, posible to send an Entity in a Delete call, but still, don´t now if it should be better to ask them to change their method
As told in the coments by Ewramner and VoiceOfUnreason and in the edits:
1: The answer about how to make this was found in an older post of StackOverflow: setEntity in HttpDelete
2: The answer about "Should I just talk with the people who made the API and ask them to change their configuration to allow us to send the info by params?" was answered by both of them. While it´s not forbidden, it´s something thats not recommended.
My course of action will be:
1: Talk with the people responsible for the API to give them info about this situation.
2: Ask our Architecture team to create a new method that will allow us to do HttpDelete calls with an entity body, just in case that we have to make more API calls like this one.
With this i think all my answers are solved.
Again, Thank you.
Is it possible to configure Spring RequestDumperFilter so that it will not log specific headers that contain sensitive information (for example the "Authorization" header)?
Looking at the source https://github.com/apache/tomcat/blob/8e2aa5e45ce13388da62386e3cb1dbfa3b242b4b/java/org/apache/catalina/filters/RequestDumperFilter.java it appears there is no way to do that:
Enumeration<String> hnames = hRequest.getHeaderNames();
while (hnames.hasMoreElements()) {
String hname = hnames.nextElement();
Enumeration<String> hvalues = hRequest.getHeaders(hname);
while (hvalues.hasMoreElements()) {
String hvalue = hvalues.nextElement();
doLog(" header", hname + "=" + hvalue);
}
}
But it would be very easy to copy that file and modify it to do what you want.
I'm stuck with a SearchTemplate request, until now I've been able to write queries through the QueryBuilder and execute them calling the "search" method of the RestHighLevelClient java client, but when I try to execute the searchTemplate method I get a parse exception from the server "request body or source parameter is required".
So far I've been reading the documentation but nothing, the guide about the SearchTemplate is very poor.
This is how I'm currently trying to follow the basic steps from the official documentation:
SearchTemplateRequest request = new SearchTemplateRequest();
request.setRequest(new SearchRequest(indexPI));
request.setScriptType(ScriptType.INLINE);
request.setScript( "{" +
" \"query\": { \"match\" : { \"{{field}}\" : \"{{value}}\" } }," +
" \"size\" : \"{{size}}\"" +
"}");
Map<String, Object> scriptParams = new HashMap<>();
scriptParams.put("from","");
scriptParams.put("size","");
scriptParams.put("field", "title");
scriptParams.put("value", "elasticsearch");
scriptParams.put("size", 5);
request.setScriptParams(scriptParams);
SearchTemplateResponse response = elasticSearchClient.searchTemplate(request,
RequestOptions.DEFAULT);
The error I get:
Elasticsearch exception [type=parse_exception, reason=request body or source parameter is required]
At this point, I'm trying to understand how to set the request body for the above request and actually wondering if it is possible to do.
Any clue about what is missing besides the "unsettable" request body from the exception?
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.
This is my FQL. What it does is it receives the post based on post_id, and also returns if post was made by user or page. User or page is returned based on id of the one who posted the post, which is returned by first FQLQuery.
StringBuilder fqlQuery = new StringBuilder();
fqlQuery.append("SELECT "
+ FacebookGraphApi.FQL_STREAM_SELECT
+ " FROM stream WHERE post_id=\"");
fqlQuery.append(rmtId);
fqlQuery.append("\"");
HashMap<String, String> querys = new HashMap<String, String>();
querys.put("messages", fqlQuery.toString());
querys.put(
"users",
"SELECT "
+ FacebookGraphApi.FQL_USER_SELECT
+ " FROM user WHERE uid IN (SELECT actor_id FROM #messages)");
querys.put(
"pages",
"SELECT "
+ FacebookGraphApi.FQL_PAGE_SELECT
+ " FROM page WHERE page_id IN (SELECT actor_id FROM #messages)");
Now what i would like to do is the same using RESTFB Batch Request API
BatchRequest firstRequest = new BatchRequestBuilder(rmtId)).build();
BatchRequest secondRequest = new BatchRequestBuilder(poster_id).build();
List<BatchResponse> batchResponses =
facebookClient.executeBatch(firstRequest,secondRequest);
These are 2 batches that executes, first one returns the post, and it contains "from", that contains poster_id of the one who posted, but i dont know how to put that poster_id from first batch to second batch so it would return poster information.
Any help would be appreciated, thanks.
Just to post the answer,
first request should contain a name method on which u depend on the other request, and search on second request that depends on first ids like this.
?ids={result=name-of-method:$.data.id}