I'm trying to upload an image to an http server that supposedly accepts files in "the standard way", whatever that means. I've combined a bunch of examples from the Internet, each of which does a tiny part of what I want, into this solution.
'srcBitmap' is a byteArray containing the JPG data.
val response: HttpResponse = httpClient.submitFormWithBinaryData(
url = URLUploadFile,
formData = formData {
append("bitmapName", "image.jpg")
append("image", srcBitmap, Headers.build {
append(HttpHeaders.ContentType, "image/jpg")
append(HttpHeaders.ContentDisposition, "filename=image.jpg")
})
},
block = {
headers {
append(HttpHeaders.ContentType, contentTypeString)
append(HttpHeaders.CacheControl, "no-cache")
append("my-app-authtoken", PREFKEY_AUTHTOKEN)
append("my-app-id", PREFKEY_USERID)
}
contentType(ContentType.Application.Json)
body = jsonBody.toString()
})
The main "body" part is some json that gets passed in the 'block' parameter. This data is arriving safely as intended.
But the binary data of the image itself is either not showing up on the server side, or is being ignored by the server because I don't have some "key" value set appropriately.
Is this the correct way to upload a file using Ktor? And if not, what am I doing wrong?
The second append call is a correct way of sending a part with the name image and the filename image.jpg. The problem is that you can't send both application/json and multipart/form-data content in one request.
Actually yours is a correct way, I was facing the same problem with my back-end guy that he receives my request as a byteArray file and couldn't recognized. So what I did was specify the files directly to the body instead of using submitFormWithBinaryData, as below..
'srcBitmap' is a byteArray containing the JPG data.
httpClient.post<RESPONSE>(URL) {
headers {
append(HttpHeaders.Accept, ContentType.Application.Json)
}
body = MultiPartFormDataContent(
formData {
this.append(FormPart("bitmapName", "image.jpg"))
this.appendInput(
key = "image",
headers = Headers.build {
append(
HttpHeaders.ContentDisposition,
"filename=image.jpg"
)
},
) { buildPacket { writeFully(srcBitmap) } }
}
)
}
Related
i am trying to upload image to parse server
but it return
https://parsefiles.back4app.com/ehUKQVObBspFk0MBFNSSg3MwLJofpeoFtDhQNIgS/2f345485e2e5cc757c80cfdacf138871_hello.png
whitch contains image cant be displayed because it contain error
it success on uploading image but image is corrupted
note : when i use same code to upload pdf or mp3 files it works well
val response = client.post<HttpResponse>("https://encyriptionapp.b4a.io/parse/files/hello.png") {
headers.append("X-Parse-Application-Id", PublicData.Application_Id)
headers.append("X-Parse-REST-API-Key", PublicData.REST_API_Key)
body = MultiPartFormDataContent(
formData {
append("file", file/*bytes*/, Headers.build {
append(HttpHeaders.ContentType, "image/png")
})
}
)
}
I'm building this android app where I need to send images to the server. I'm using retrofit to do so. I get image path as its answer in this stack overflow question Get file path of image on Android and send images as shown here How to upload an image file in Retrofit 2. When I decode a file that I create in the android studio it is valid, but when I send it to my .net rest API it is null. Here is the rest API code, the idea is to get an image if it's null send an image that says it's null, and if not save that image and send it back. The part where I'm sending it back works perfectly, that is I receive an image sent to android, but the image that is sent from android is null.
[Route("post")]
public async Task<IActionResult> PostSlika(IFormFile formFile)
{
if (formFile is null)
{
var stream2 = new FileStream(Path.Combine(_host.WebRootPath, "Images/null_je.jpg"), FileMode.Open);
return File(stream2, "image/jpg");
}
using (var stream = System.IO.File.Create(Path.Combine(_host.WebRootPath, "Images/1.jpg")))
{
await formFile.CopyToAsync(stream);
}
var stream1 = new FileStream(Path.Combine(_host.WebRootPath, "Images/1.jpg"), FileMode.Open);
return File(stream1, "image/jpg");
}
}
I guess there is a conversion problem when converting data to IFormFile. But first check the incomming data with Base64String. I mean:
[Route("post")]
public async Task<IActionResult> PostSlika(string formFileStr)
{
//Convert formFileStr from Base64String to IFormFile
}
Note: you should send Base64String to your service to test it.
If that is OK but you don't want to use this approach then you can use UriTemplate like this:
[WebInvoke( Method= "POST",
//These two parameters are not necessary, but you can use them:
RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json,
//
UriTemplate = "PostSlika/?q={formFile}")]
public async Task<IActionResult> PostSlika(IFormFile formFile)
{
//your codes here
}
Then address to your service method should be changed a little:
{Your Service Address}/PostSlika/?q={object of IFormFile}
I'm trying to upload an image file to a server and have been using this method to "append" the binary file bytes to the message. 'srcBitmap' is a byteArray containing the image bytes.
formData = formData {
append("image", srcBitmap, Headers.build {
append(HttpHeaders.ContentType, "image/jpg")
append(HttpHeaders.ContentDisposition, "filename=image.jpg")
})
In other examples on the web they do it this way.
formData {
appendInput(key = ICON_FILE_PART, headers = Headers.build {
append(HttpHeaders.ContentDisposition, "filename=${appId}_ic")
}) {
buildPacket { writeFully(icon.toByteArray()) }
}
})
What's the difference between these two ways (append vs. 'buildPacket')? Why would you use one over the other?
These are just different ways of making multipart binary parts. Using buildPacket you can build arbitrary byte packets with no knowledge of their size. If you need to create a binary part from a file then I recommend using the first option because it's straightforward and easier to understand.
I am having a problem with uploading an image in ios apollo client. after I upload an image I get a GraphQlError "createReadStream is not a function".
I could not figure out what has gone wrong?
Mutation
mutation UploadPhoto($input: UploadPhotoInput){
uploadClientPhoto(input: $input){
photo
}
}
Type Detail
type UploadPhotoInput {
photo: Upload
}
type UploadPhotoResponse {
photo: String
}
Following code is not working
class Network {
static let shared = Network()
private lazy var networkTransport = HTTPNetworkTransport(url: URL(string: "http://192.168.10.29:5001/graphql")!, session: .init(configuration: URLSessionConfiguration.default))
private(set) lazy var apolloCient = ApolloClient(networkTransport: networkTransport)
}
Upload image
if let data = singlePhoto.image.jpegData(compressionQuality: 0.8) {
let name = UUID().uuidString
let file = GraphQLFile(fieldName: "\(name)", originalName: "\(name).png",mimeType: "image/png" ,data: data)
let uploadInput = UploadPhotoInput(photo: file.originalName)
let uploadMutation = UploadPhotoMutation(input: uploadInput)
Network.shared.apolloCient.upload(operation: uploadMutation, context: nil, files: [file]) { (result) in
switch result {
case .success(let success):
print(success.data)
case .failure(let error):
print(error.localizedDescription)
}
}
}
This certainly sounds frustrating. I've heard of similar issues with other networking clients, though.
Sounds like apolloCient.upload won't send a GraphQL Multipart Request.
Looks like this blog post covers exactly how to set this up - even including an example repo made for React Native.
Hope that's helpful!
I'm using nativescript-imagepicker plugin to select images from phone gallery. One of the things this plugin allows me to get, is the path to the file.
I need to be able to upload this selected file to a server, using form data. For that i need to create a file object first.
How can i use a file path, to create a file object?
For uploading images from the photo gallery I would highly suggest using Nativescsript background http. To upload the images to the server you will have to save them within the app so that they can be uploaded. I followed the example shown here Upload example.
Once you have saved the images locally if you want additional data you will need to use multipartUpload and construct a request that would look something like this.
let BackgroundHTTP = require('nativescript-background-http')
let session = BackgroundHTTP.session('some unique session id')
let request: {
url: 'your.url.to/upload/images',
method: 'POST',
headers: {
'Content-Type': 'application/octet-stream'
}
description: 'Uploading local images to the server'
}
//photos should have at least the filename from when you saved it locally.
let params = []
photos.forEach(photo => {
params.push({name: photo.name, filename: photo.filename, value: 'ANY STRING DATA YOU NEED'})
}
let task = session.multipartUpload(params, request)
task.on('progress', evt => {
console.log('upload progress: ' + ((evt.currentBytes / evt.totalBytes) * 100).toFixed(1) + '%')
}
task.on('error', evt => {
console.log('upload error')
console.log(evt)
}
task.on('complete', evt => {
//this does not mean the server had a positive response
//but the images hit the server.
// use evt.responseCode to determine the status of request
console.log('upload complete, status: ' + evt.responseCode)
}