15

I'm trying to accomplish a multipart file upload using feign, but I can't seem to find a good example of it anywhere. I essentially want the HTTP request to turn out similar to this:

...
Content-Type: multipart/form-data; boundary=AaB03x

--AaB03x
Content-Disposition: form-data; name="name"

Larry
--AaB03x
   Content-Disposition: form-data; name="file"; filename="file1.txt"
   Content-Type: text/plain

... contents of file1.txt ...
--AaB03x--

Or even...

------fGsKo01aQ1qXn2C
Content-Disposition: form-data; name="file"; filename="file.doc"
Content-Type: application/octet-stream

... binary data ...

------fGsKo01aQ1qXn2C--

Do I need to manually build the request body, including generating the multipart boundaries? That seems a bit excessive considering everything else this client can do.

btidwell
  • 427
  • 1
  • 3
  • 10

6 Answers6

9

No, you don't. You just need to define a kind of proxy interface method, specify the content-type as: multipart/form-data and other info such as parameters required by the remote API. Here is an example:

public interface FileUploadResource {

    @RequestLine("POST /upload")
    @Headers("Content-Type: multipart/form-data")
    Response uploadFile(@Param("name") String name, @Param("file") File file);

} 

The completed example can be found here: File Uploading with Open Feign

NangSaigon
  • 1,253
  • 12
  • 14
6

For spring boot 2 and spring-cloud-starter-openfeign use this code:

@PostMapping(value="/upload", consumes = "multipart/form-data" )
QtiPackageBasicInfo upload(@RequestPart("package") MultipartFile package);

You need to change @RequestParam to @RequestPart in the feign client call to make it work, and also add consumes to the @PostMapping.

MBozic
  • 1,132
  • 1
  • 10
  • 22
3

If you are already using Spring Web, you can try my implementation of a Feign Encoder that is able to create Multipart requests. It can send a single file, an array of files alongwith one or more additional JSON payloads. Here is my test project. If you don't use Spring, you can refactor the code by changing the encodeRequest method in FeignSpringFormEncoder.

pcan
  • 893
  • 11
  • 24
  • 1
    This is an amazing implementation. I had been breaking my head for quite a few days around using FeignClient to pass a file as well as a JSON Body in a single call and this just did it perfectly. Thank you very much. – Ajinkya Mahagaonkar Sep 12 '22 at 00:37
3

MBozic solution not full, you will also need to enable an Encoder for this:


public class FeignConfig {
     
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

    @Bean
    public Encoder feignFormEncoder () {
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }
}

@FeignClient(name = "file", url = "http://localhost:8080", configuration = FeignConfig.class)
public interface UploadClient {
    @PostMapping(value = "/upload-file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    String fileUpload(@RequestPart(value = "file") MultipartFile file);
}
Emerson Micu
  • 450
  • 8
  • 17
0

Let me add Answer for latest OpenFeign :

  1. Add dependency for Feign-Form:

    io.github.openfeign.form feign-form 3.8.0
  2. Add FormEncoder to your Feign.Builder like so:

SomeApi github = Feign.builder() .encoder(new FormEncoder()) .target(SomeApi.class, "http://api.some.org");

  1. API endpoint

@RequestLine("POST /send_photo") @Headers("Content-Type: multipart/form-data") void sendPhoto (@Param("is_public") Boolean isPublic, @Param("photo") FormData photo);

Refer : https://github.com/OpenFeign/feign-form

0

Call from one service to another service for file transfer/upload/send using feign client interface:

@FeignClient(name = "service-name", url = "${service.url}", configuration = FeignTokenForwarderConfiguration.class)

public interface UploadFeignClient {

@PostMapping(value = "upload", headers = "Content-Type= multipart/form-data", consumes = "multipart/form-data")
public void upload(@RequestPart MultipartFile file) throws IOException;

}

**Actual API:**

@RestController

@RequestMapping("upload")

public class UploadController {

@PostMapping(value = "/upload", consumes = { "multipart/form-data" })   
public void upload(@RequestParam MultipartFile file) throws IOException {

//implementation

}

}
cigien
  • 57,834
  • 11
  • 73
  • 112
Murali S
  • 17
  • 1