To support file uploads, follow these three steps to define the interface.

Proto Request

Define field as bytes type:

message UploadBookCoverToLocalRequest {

  option (hope.swagger.schema) = {
    json_schema: {
      description: "upload a cover of book to the local file system";
    };
  };

  int64 id = 1 [(hope.swagger.field) = {
    description: "id of this book";
    empty: FALSE;
  }];

  bytes file = 2 [(hope.swagger.field) = {
    description: "file of this book must be a image(jpg|png) etc";
    empty: FALSE;
  }];
}

Define Path

Define Path as:

  1. consumes: "multipart/form-data" must 💯
  2. post must 💯
rpc UploadBookCoverToLocal (com.novel.book.proto.api.admin.request.UploadBookCoverToLocalRequest) returns (google.protobuf.Empty) {
    option (hope.swagger.operation) = {
      post: "/upload-book-cover";
      description: "Upload a book cover to local file system";
      priority: LOW;
      consumes: "multipart/form-data";
      authorization:{
        rbac:{
          predefined_role_checker: PLATFORM
        }
      }
    };
  }

Wire Generate

  "/admin/book/upload-book-cover" : {
      "post" : {
        "tags" : [ ],
        "summary" : "",
        "description" : "Upload a book cover to local file system",
        "operationId" : "AdminBookService#UploadBookCoverToLocal",
        "parameters" : [ ],
        "requestBody" : {
          "content" : {
            "multipart/form-data" : {
              "schema" : {
                "type" : "object",
                "$ref" : "#/components/schemas/UploadBookCoverToLocalRequest"
              }
            }
          }
        }
      }
    }
Post File

Parameter Multipart as generic type of the body class:

public class UploadBookCoverToLocalRequest<Multipart> {
  @hope.common.service.annotation.Multipart
  @NotNull
  @Schema(
      description = "file of this book must be a image(jpg|png) etc",
      requiredMode = Schema.RequiredMode.REQUIRED
  )
  protected Multipart file;
}

The implementation class will be generated by stub at application module.

Stub Generate

Concrete Multipart parameter org.springframework.web.multipart.MultipartFile:


import javax.annotation.Generated;
import org.springframework.web.multipart.MultipartFile;

@Generated("H.O.P.E. Infra Team")
public class UploadBookCoverToLocalRequestMultipart extends UploadBookCoverToLocalRequest<MultipartFile> {
}

Handle the file save logic in your logic:

/**
   *
   * Authorization:
   *
   * <ul>
   * 	<li>PredefinedRoleCheckerType: PLATFORM</li>
   * </ul>
   * @apiNote
   * 	<p>{@code /admin/book/upload-book-cover}
   * 	<p>{@code Upload a book cover to local file system}
   */
  default void uploadBookCoverToLocal(SimpleResultBuilder<String> builder,
      UploadBookCoverToLocalRequestMultipart uploadBookCoverToLocalRequestMultipart) {
    builder.notImplemented();
  }

Video Guide

  1. ApiHug101-Bilibili
  2. ApiHug101-Youtube