Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what's the correct way to send a file from REST web service to client?

I've just started to develop REST services, but I've come across a difficult situation: sending files from my REST service to my client. So far I've gotten the hang of how to send simple data types (strings, integers, etc) but sending a file is a different matter since there are so many file formats that I don't know where I should even begin. My REST service is made on Java and I'm using Jersey, I'm sending all the data using the JSON format.

I've read about base64 encoding, some people say it's a good technique, others say it isn't because of file size issues. What is the correct way? This is how a simple resource class in my project is looking:

import java.sql.SQLException; import java.util.List;  import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Request; import javax.ws.rs.core.UriInfo;  import com.mx.ipn.escom.testerRest.dao.TemaDao; import com.mx.ipn.escom.testerRest.modelo.Tema;  @Path("/temas") public class TemaResource {      @GET     @Produces({MediaType.APPLICATION_JSON})     public List<Tema> getTemas() throws SQLException{          TemaDao temaDao = new TemaDao();                 List<Tema> temas=temaDao.getTemas();         temaDao.terminarSesion();          return temas;     } } 

I'm guessing the code for sending a file would be something like:

import java.sql.SQLException;  import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces;  @Path("/resourceFiles") public class FileResource {      @GET     @Produces({application/x-octet-stream})     public File getFiles() throws SQLException{ //I'm not really sure what kind of data type I should return          // Code for encoding the file or just send it in a data stream, I really don't know what should be done here          return file;     } } 

What kind of annotations should I use? I've seen some people recommend for a @GET using @Produces({application/x-octet-stream}), is that the correct way? The files I'm sending are specific ones so the client doesn't need to browse through the files. Can anyone guide me into how am I supposed to send the file? Should I encode it using base64 to send it as a JSON object? or the encoding isn't necessary to send it as a JSON object? Thanks for any help you may give.

like image 512
Uriel Avatar asked Sep 02 '12 21:09

Uriel


People also ask

Can an API return a file?

Return a File in ASP.NET Core Web API In ASP.NET Core, a Web API action method usually returns an ActionResult object. When we want to return a file response, we can explicitly set the return type for the action method to be FileResult , which is a type inherited from ActionResult .


2 Answers

I don't recommend encoding binary data in base64 and wrapping it in JSON. It will just needlessly increase the size of the response and slow things down.

Simply serve your file data using GET and application/octect-streamusing one of the factory methods of javax.ws.rs.core.Response (part of the JAX-RS API, so you're not locked into Jersey):

@GET @Produces(MediaType.APPLICATION_OCTET_STREAM) public Response getFile() {   File file = ... // Initialize this to the File path you want to serve.   return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)       .header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional       .build(); } 

If you don't have an actual File object, but an InputStream, Response.ok(entity, mediaType) should be able to handle that as well.

like image 69
Philipp Reichart Avatar answered Oct 13 '22 20:10

Philipp Reichart


If you want to return a File to be downloaded, specially if you want to integrate with some javascript libs of file upload/download, then the code bellow should do the job:

@GET @Path("/{key}") public Response download(@PathParam("key") String key,                          @Context HttpServletResponse response) throws IOException {     try {         //Get your File or Object from wherever you want...             //you can use the key parameter to indentify your file             //otherwise it can be removed         //let's say your file is called "object"         response.setContentLength((int) object.getContentLength());         response.setHeader("Content-Disposition", "attachment; filename="                 + object.getName());         ServletOutputStream outStream = response.getOutputStream();         byte[] bbuf = new byte[(int) object.getContentLength() + 1024];         DataInputStream in = new DataInputStream(                 object.getDataInputStream());         int length = 0;         while ((in != null) && ((length = in.read(bbuf)) != -1)) {             outStream.write(bbuf, 0, length);         }         in.close();         outStream.flush();     } catch (S3ServiceException e) {         e.printStackTrace();     } catch (ServiceException e) {         e.printStackTrace();     }     return Response.ok().build(); } 
like image 33
john 4d5 Avatar answered Oct 13 '22 20:10

john 4d5