I have a Quarkus service where I'm trying (to some extent) to mimic the S3 API.
I noticed that the multipart upload in S3 goes something like this:
POST bucket.host.com /KEY?uploads // signifies that a multipart upload on KEY is starting
// and returns an uploadId for it
PUT bucket.host.com /KEY?uploadId=UPLOADID&partNumber=2 // uploads part 2 of the file,
// content is in request body
PUT bucket.host.com /KEY?uploadId=UPLOADID&partNumber=1 // upload part 1
POST bucket.host.com /KEY?uploadId=UPLOADID // signifies that the multipart upload is completed
An "atomic" file upload (that is, no multipart, file is just uploaded in one go) "reuses" the PUT path, so to upload a file in that way you just do a PUT on the URL and skip both the query parameters.
I'm not going to use the "bucket is embedded in the host name" approach and instead it will be part of the request URL.
So what I currently have is a resource class that looks like this (simplified and bucket is called "project" in my case and KEY is called "path"):
@Path("/fts")
class FileTransferService(
@ConfigProperty(name = "fts.project.root")
private val projectRoot: String
) {
@POST
@Path("{project}/{path:.*}")
@Produces(MediaType.APPLICATION_JSON)
fun multipartFileUpload(
@PathParam project: String,
@PathParam path: String,
@QueryParam("uploads") uploads: String?,
@QueryParam("uploadId") uploadId: String?
): String {
// Here I'll have to check whether uploads or uploadId is set
// and determine the path to take with some if/else statements.
}
@PUT
@Path("{project}/{path:.*}")
@Produces(MediaType.APPLICATION_JSON)
fun upload(
@PathParam project: String,
@PathParam path: String,
@QueryParam("uploadId") uploadId: String?,
@QueryParam("partNumber") partNumber: String?,
body: InputStream
): String {
// Here I'll need to check uploadId and/or partNumber to determine
// whether this is an "atomic file upload" or a single part of a
// multi part upload and determine the path to take with if/else again.
}
}
As you see in the comments in the above code I have to do some if/else checking and go different routes depending on whether or not the query parameters are set.
This bugs me. I would rather have different @POST methods, one catching the case where the uploads
parameter is set, and another one if the uploadId
parameter is set.
I tried having multiple methods where one specifies the QueryParameter and another one doesn't but that doesn't seem to work. I get an information message in the quarkus log saying that multiple matches were found for the path and one is picked randomly (probably just the first one).
So I'm guessing that if this is at all possible, it would be by somehow putting the query parameters into the @Path
annotation but I have not been able to find how I would do that. A probable reason for that is that it just isn't possible but I wanted to ask here and get confirmation.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…