I've got the following setup. I have to send an image over http to a browser or other device. The tricky thing about the whole it is, that I have very limited control over the http-packet creation.
I only can provide the content type field and the message body as a string.
Is there a way how I could create an http-packet containing a image with this limited configuration facilities?
You need to have:
Content-Type as 'application/image'
data in body as binary
With your limitation as you can have only strings in body, an image cannot be sent in response.
You could convert your image to a base64 string: http://www.base64-image.de/
Related
I am trying to create an application, where documents are uploaded from the Angular application and send to the Spring Rest Endpoint, which will save the document in Database. I could see two options
Creating an endpoint which accepts base encoded array of bytes in the body of the POST request.
Creating the endpoint to accept Multipart file
Which one is better in terms of performance and why ? Please note, my document size can be from a couple of MBs to 25 MB.
Base64 is a way to encode binary data into an ASCII character format by translating it into a radix-64 representation.
I recommend you that never use Base64 for large file/data upload to the server because it converts whole data and posts it to the server.
An the other hand, Multipart is a way to upload the file to a server in the form of parts which are in bytes. Multipart/form-data is applied to a form though, so you can send everything in a multi-part form, including "regular" data also.
So, I think this can be useful for you:
#PostMapping("/api/update")
public ResponseEntity upload(#NotNull #NotEmpty #RequestParam("file") MultipartFile file) {}
In restfull WS, how to tell client to send only csv and text format file.
In content-type header, client set the format in which it is sending request and in Accept header, client set the format in which it want to accept response.
But how to tell client to send only content-type csv or file ? Is this through some documentation ?
The 415 status code seems to be suitable for this situation:
6.5.13. 415 Unsupported Media Type
The 415 (Unsupported Media Type) status code indicates that the
origin server is refusing to service the request because the payload
is in a format not supported by this method on the target resource.
The format problem might be due to the request's indicated
Content-Type or Content-Encoding, or as a result of inspecting the
data directly.
The response payload could contain a list of the media types supported by the server.
Image you have an endpoint called /textfiles - the developer using your API is usually reading your documentation on how to implement this endpoint. Unless you're not doing some auto-discovery magic (which I guess is still not common).
If we take Facebook for example, they just state in their documentation which files you can send:
We accept the following files: 3g2, 3gp, 3gpp, [...]
Your question:
But how to tell client to send only content-type csv or file ?
is also a bit unclear. When the user has sent the request, he already attached the files he thought he could send. So here you would rather send an error with a message, which files are allowed. So are we talking about some "pre"-requests here?
From a backend developers point of view I can just tell you: It's in the documentation. Handle errors properly, document and your implementing developer will not hate you :)
if i develop a restful application using spring i would set the produces attribute to return csv or plain text ( https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html) . if the client tries to request a resource other than csv or text it will recieve an error . probably 415
Say I have this HTML:
<img src="http://example.com/pic"/>
What I would like to do is have example.com/pic map to an AWS API Gateway endpoint.
That endpoint would then call a lambda function.
That lambda function would read a random image from an s3 bucket and return it.
So my aim is to use a STANDARD HTML image tag and end up with an image from an s3 bucket but going via some decision code in the lambda to decide the image to return.
I know you can use s3 to serve static content directly (hence the lambda to make the decision about what image). I also know I could do stuff in the lambda like b64 encode the response and then handle it on the client but I am aiming to use the standard HTML IMG tag.
Is this possible?
I've tried using the ResponseStreamHandler (Java SDK) for the lambda and returning the byte array of the image and also added the API gateway config to not map the output to JSON, but nothing seems to work!
It seems AWS has simplified this process, so that many answers are outdated and/or overly complicated.
This is how I got Lambda to return an image through the API Gateway, as of June 2018:
1) In API Gateway, enable Use Lambda Proxy integration for your API. (This setting is located on the Integration Request section, where you had set the type to Lambda.)
2) In API Gateway, select your API and click Settings. In Binary Media Types add */*. (Note: I tried adding simply 'image/jpeg', but it seems to require */* to get all of this to work)
3) Be sure to deploy your API, otherwise your changes will not be live. (In API Gateway, select your API, then Actions > Deploy API).
4) In your Lambda code, return your image in Base64 encoding (this example is C# code):
// set the Content-type header
// set to whichever image type you're returning
var headersDic = new Dictionary<string, string>();
headersDic.Add("Content-type", "image/jpeg");
// return the response object that APIGateway requires
return new APIGatewayProxyResponse
{
StatusCode = 200,
Headers = headersDic,
// return the image in Base64 encoding
Body = Convert.ToBase64String(...your image data...),
IsBase64Encoded = true
};
Done.
If you've setup your API to not require authentication, simply type your API link into your browser, and it will display the image. Or put the API link into an IMG tag. e.g. <img src="https://asdf.execute-api.us-east-1.amazonaws.com/live/myapi" />
Note: Even though in step 2 you set the Binary Media Types to */*, API Gateway will still return text if that is what your Lambda is returning.
Luckily, now AWS API Gateway supports binary data, though you also need to update your resource method through the CLI as it is not yet implemented in the Console. This is what you need to do:
In the Method Response of your method
Set Content-Type as image/jpeg in HTTP 200 Status Response
Header
In the Integration Response of your method
Set Content-Type as 'image/jpeg' in Header Mappings. Mind the quotes!
With the AWS CLI, set contentHandling attribute to CONVERT_TO_BINARYon your Integration Response
Check to entire process in this great step-by step guide: https://stackoverflow.com/a/41434295/720665
I've run in to a similar problem. As mentioned you currently can't directly return your image in binary format from your API Gateway endpoint, which would be required for the browser to display it correctly.
However, I solved this by instead having API Gateway return a 302 Redirect, pointing to the correct file in S3. You can have your Lambda function return the url to the file, which is later on mapped to the Location header in API Gateway. The browser will follow the redirect and display the image properly.
There are several ways to implement the redirect, but I did as follow:
Lambda returns an object with the target image like so:
function handler(event, context) {
context.succeed({
location: "https://[bucket-name].s3-eu-west-1.amazonaws.com/myimage.png" });
});
}
Remove the normal '200' Method Response Status from The Integration Response in API Gateway. Replace it with a '302' response status and add the 'Location' header mapped to value 'integration.response.body.location'
Add the 302 status to the Method Response as well
Just to be clear, the client does two different requests:
The first to get the HTML (including the image url).
The second to fetch the image data from the url.
In other words, the image data is not inlined in the HTML.
Based on this knowledge you can have a Lambda (behind the API gateway) as you suggest. The Lambda implementation can have some logic that determines the url to the image stored in S3. However, the Lambda returns JSON data and not HTML (there are workarounds such as return the html in a variable) which makes things trickier, especially for large HTML pages.
I suggest a slightly different approach, since just receiving an image tag will not get you far. I assume you will inline the image tag in a HTML document, probably by using JavaScript. Then you might as well let the API Gateway / Lambda request return a JSON document with the image url and let the JavaScript either update an existing image tag with the new url or generate the tag for you.
It currently isn't possible because you cannot return binary data through the AWS API Gateway.
For this to work, the lambda function would need to return the image data as binary blob, and some meta-information such as the image content type. Then, AWS API Gateway would need to be able to map this to the HTTP response. For example:-
lambda returns:
{
contentType: 'image/png',
image: "encoded binary data"
}
then API gateway would need to map contentType to the 'content-type' header of the response, and put the image data in the body of the response with the right encoding and length.
Unfortunately, it doesn't do this right now. It only maps text encodings like application/json or application/xml as the response type (it is designed for APIs after all).
You could very easily achieve this using ElasticBeanstalk where you have a lot more control over the http response.
I resolved this problem be reconsidering my design. The underlying thinking is that Lambdas are good computing units and bad file servers.
I changed
Client > APIGW > Lambda > Image
into
Client > APIGW > Lambda > SignedURL
then Client(SignedURL) > Image
Since my client was web based, everything was easier after that shift
I am working on a use case where I am displaying user's messages on a JSP. Details of the flow are:
All the messages will be shown in a table with icon for attachments
When the user clicks on attachment, the file should get downloaded.
If there is more than one attachment, user can select the required
one to download.
The attachments will be stored on the local filesystem and the path for the attachments will be determined by the system.
I have tried to implement by referring to these SO questions:
Input and Output binary streams using JERSEY?
Return a file using Java Jersey
file downloading in restful web services
However, it's not solving my purpose. I have the following questions:
Is it possible to send message data (like subject, message, message id, etc) along with the attachments (Inputstream) in one response?
If yes, what needs to be the MediaType for #Produces annotation in my resource method? Currently my resource is annotated with #Produces(MediaType.APPLICATION_JSON). Will this work?
How to send the file data in the response?
Any pointers appreciated. TIA.
You can add custom data to the response Header, so yes you are able to send such message data. Add the data to the response Header.
#Produces(MediaType.APPLICATION_JSON) will not work, unless the clients will accept JSON as a file, what they should and will not do ;)
The correct MediaType depends on what kind of file you want to submit.
You can use the default MediaType / MIME-Type MediaType.APPLICATION_OCTET_STREAM / application/octet-stream (Is there a “default”
MIME type?) but I think it's better to use the correct and exact MIME-Type for your file.
You will find working examples for sending file data with jersey in Input and Output binary streams using JERSEY? - so there is no need to answer this again :)
Hope this was helpful somehow, have a nice day.
I want to send the contents of a file as part of a http request using Apache HttpClient and I could not figure out how to pass on the file contents in the request body.
You didn't specify the format....
Most likely, you want to send a POST request, the contents will be multipart/form-data MIME type. This emulates what a browser sends from an <INPUT type="file" ...> form element. This requires some pretty sophisticated parsing on the server side to extract the multiple parts from the body and correctly extract the file data from the other fields (if any). Fortunately, commons-fileupload does this perfectly. The first answer regarding FilePart is exactly right.
Alternatively, you could simply post the raw contents of a file as the body of the request by using an InputStreamRequestEntity. This may be much simpler if you're writing your own server side to receive the data. The server side is as simple as streaming the request's InputStream to disk. I use this technique for uploads with Google Gears.
Check out FilePart and related.
Here's the sample.