oatpp / oatpp-swagger

OpenApi 3.0.0 docs + Swagger UI for oatpp services
https://oatpp.io/
Apache License 2.0
94 stars 53 forks source link

How to return a file in the swagger ? #40

Closed remioukrat closed 3 years ago

remioukrat commented 3 years ago

I have a DTO with just a binary inside

DTO_FIELD(oatpp::swagger::Binary, file);

my endpoint documentation is like this:

    ENDPOINT_INFO(SampleUploadDownloadImage)
    {
        info->summary = "Test image";
                // I use a multipart because if I use a type mime for image is not managed
        info->addConsumes<Object<MultipartDto>>(MimeType::Multipart::MultipartFormData);
        info->addResponse<Object<MultipartDto>>(Status::CODE_200, MimeType::Multipart::MultipartFormData);
    }

I try to return a Multipart like this:

        Action Response()
        {
            auto pData = std::make_shared<MultipartDto>();
                        // I use a file previously saved
            pData->file->loadFromFile(PathToMyFile);
            return _return(controller->createDtoResponse(Status::CODE_200, Object<MultipartDto>(pData)));
        }

and I have a error 500. I would like to know if there is a solution to return a file in the swagger ?

lganzzzo commented 3 years ago

Hello @remioukrat ,

What is the error message for your 500?

Also, you are using createDtoResponse, and I assume that you have a json mapper set for your controller. So you are not returning a multipart but json instead.

To return a multipart response, you have to manually create multipart and set all of its parts. You can use the following function as an example:

Create Multipart Function


#include "oatpp/web/mime/multipart/PartList.hpp"
#include "oatpp/web/protocol/http/outgoing/MultipartBody.hpp"

...

  static std::shared_ptr<oatpp::web::mime::multipart::PartList>
  createMultipart(const std::unordered_map<oatpp::String, oatpp::String>& map) {

    auto multipart = oatpp::web::mime::multipart::PartList::createSharedWithRandomBoundary();

    for(auto& pair : map) {

      oatpp::web::mime::multipart::Headers partHeaders;
      auto part = std::make_shared<oatpp::web::mime::multipart::Part>(partHeaders);
      multipart->writeNextPartSimple(part);
      part->putHeader("Content-Disposition", "form-data; name=\"" + pair.first + "\"");
      part->setDataInfo(std::make_shared<oatpp::data::stream::BufferInputStream>(pair.second));

    }

    return multipart;

  }

Send Multipart in the Response

  ENDPOINT_ASYNC("GET", "/multipart", GetMultipart) {

    ENDPOINT_ASYNC_INIT(GetMultipart)

    Action act() override {

      std::unordered_map<oatpp::String, oatpp::String> map;

      map["part1"] = "data1";
      map["part2"] = "part2";

      auto responseBody = std::make_shared<oatpp::web::protocol::http::outgoing::MultipartBody>(createMultipart(map));
      return _return(OutgoingResponse::createShared(Status::CODE_200, responseBody));

    }

  };
remioukrat commented 3 years ago

@lganzzzo Thank you for the answer. When I return the answer, I would like to return a file inside the swagger or an image using swagger image rendering. I understand that I return a json. But I would like to have the body in an attachment not mixed with headers.

part->putHeader("content-disposition", "attachment; filename=\"" + key + "\"");
part->putHeader("content-type", "image/jpeg;"

I have downloaded the response and I have removed the headers but the image can’t be displayed. I guess that I have made something wrong when I have filled my data like this

map["part"] = m_bufferStream->toString();
lganzzzo commented 3 years ago

Hey @remioukrat ,

I guess you don't need multipart to return an image. Just return a binary

oatpp::String imgBuffer = getImageBuffer();

auto response = createResponse(Status::CODE_200, imgBuffer);
response->putHeader("content-type", "image/jpeg");
return response;
remioukrat commented 3 years ago

Hey @lganzzzo ,

Thanks it works correctly, because I have returned it inside the multipart through createDtoResponse and I have had always a broken image. With the createResponse, it works ;)