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!
Related
I am developing a flutter app with backend running in localhost.
I am using http package for making http calls. I am creating the Uri like this:
Uri.https("localhost:8080", "api/v1/login");
but this Uri.https gives error, instead I need to use Uri.http.
The problem is when the app is ready for production I will have to manually edit code everywhere to use Uri.https instead of Uri.http.
Is there a better way to handle this?
You can simple use kReleaseMode to detect you are in release mode or not.
String baseUrl;
if (kReleaseMode) {
baseUrl = 'https://example.com';
} else {
baseUrl = 'http://localhost';
}
Uri uri = Uri.parse('$baseUrl/api/v1/login');
you can do it like this:
var baseUrl = 'http://localhost:8080/';
Future<void> _fetchData() async {
final response = await http.get(Uri.parse('$baseUrl/api/v1/login'));
print(response.body);
}
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) } }
}
)
}
In my Flutter mobile app while loading profile image of users through NetworkImage(), I am getting 403 status code in response.
How can I handle this by displaying an Image from my assets folder in case of 403 status code or if image URL is broken etc.
Currently I've handled it by sending a HTTP GET request to the image URL and checking if the status code is 200. If it is 200 I use the NetworkImage() or else I use AssetImage() to load the image and use a FutureBuilder() to build the Widget.
While this works perfectly, I feel this a lot of trouble for handling such a small scenario and it can be done in a better way that I am unaware of.
What is the best way to handle such scenarios?
Please try below approach. Here, If image is available, It will load network image else it will redirect to the error callback. In error callback you can return the widget you want. In your case, you want to load from asset so you can use it like as below. If you want to check error status code, you need to parse the exception that I have print.
Image.network('https://www.outbrain.com/techblog/wp-content/uploads/2017/05/road-sign-361513_960_720.jpg',
errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) {
print("Exception >> ${exception.toString()}");
return Image.asset('assets/images/lake.jpg');
},
)
You did it simple for this scenario, I didnt see any trouble:
if (response.statusCode == 200) {
return NetworkImage();
} else {
return AssetImage();
}
I achieved this by using precacheImage. This will precache your image to flutter cache. It also has a onError function where you can handle errors while caching the image.
String validatedUrl;
precacheImage(
NetworkImage(urlToCheck),
context,
onError: (
exception,
stacktrace,
) {
print(exception.toString());
setState(() {
validatedUrl = '';
});
},
).whenComplete(() {
if (validatedUrl == null) {
setState(() {
validatedUrl = urlToCheck;
});
}
});
Then validatedUrl is either null, empty or carries the validated url.
null -> not validated yet
empty -> error while downloading image
url -> successfully downloaded image
Iam new in ionic with sharepoint
I have developed a Mobile app using ionic3 with sharepoint.
Now i have to get user profile picture in my app.
I have tried these are the way can't achieve here is my tried code.
First way tried like this
Passing Url:-
"https://abc.sharepoint.com/sites/QA/_layouts/15/userphoto.aspx?size=M&accountname=admin#abc.onmicrosoft.com"
Second way tried like this
Passing Url:-
These url iam geting using people picker result. PictureURL property
"https://abc.sharepoint.com/User Photos/Profile Pictures/admin_abc_onmicrosoft_com_MThumb.jpg"
These Second method always return
401 UNAUTHORIZED
Above url using to call this method.
public downloadFile(url: string, fileName: string) {
let options = this._apiHeaderForImageURL();
this._http.get(url, options)
.subscribe((data) => {
//here converting a blob to base 64 For internal view purpose in image src
var reader = new FileReader();
reader.readAsDataURL(data.blob());
reader.onloadend = function () {
console.log("Base64", reader.result);
}
//Here Writing a blob file to storage
this.file.writeFile(this.file.externalRootDirectory, fileName, data.blob(), { replace: true })
.then((success) => {
console.log("File Writed Successfully", success);
}).catch((err) => {
console.log("Error While Wrinting File", err);
});
});
}
public _apiHeaderForImageURL() {
let headers = new Headers({ 'Content-Type': 'image/jpeg' });
headers.append('Authorization', 'Bearer ' + localStorage.getItem("token"));
let options = new RequestOptions({ headers: headers, responseType: 3 });
return options;
}
The first api call worked fine result also sucess but image not displayed properly. Thats the problem iam facing.
The result comes an default image like this only.
pls help me to achieve this. Any help warmly accepted.
Iam doning long time stuff to achieve this still i cant achieve pls give some idea.
Is any other way is available to get user picture in ionic 3 using sharepoint?
I have developed an app to take a photo from the phone camera. But now I need to store the image to the phone memory into a folder created by me.
I have tried this:
var filename = Titanium.Filesystem.resourcesDirectory + "/newImageFile.jpg";
var imageFile = Titanium.Filesystem.getFile(filename);
imageFile.write(capturedImg);
But it does not apear in the gallery. How can I store the image to the phone memory and how can I create a costume folder in the phone memory to store the image?
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
NSData *imageData = [info objectForKey:UIImagePickerControllerOriginalImage];
if(picker.sourceType==UIImagePickerControllerSourceTypeCamera)
{
//to save camera roll
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest creationRequestForAssetFromImage:image];
} completionHandler:nil];
}
}
This will save image in camera roll which is taken by you
This Will Create Photo Album and save into this album.
I came up with this singleton class to handle it:
import Photos
class CustomPhotoAlbum {
static let albumName = "Titanium"
static let sharedInstance = CustomPhotoAlbum()
var assetCollection: PHAssetCollection!
init() {
func fetchAssetCollectionForAlbum() -> PHAssetCollection! {
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %#", CustomPhotoAlbum.albumName)
let collection = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions)
if let firstObject: AnyObject = collection.firstObject {
return collection.firstObject as! PHAssetCollection
}
return nil
}
if let assetCollection = fetchAssetCollectionForAlbum() {
self.assetCollection = assetCollection
return
}
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle(CustomPhotoAlbum.albumName)
}) { success, _ in
if success {
self.assetCollection = fetchAssetCollectionForAlbum()
}
}
}
func saveImage(image: UIImage) {
if assetCollection == nil {
return // If there was an error upstream, skip the save.
}
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let assetChangeRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(image)
let assetPlaceholder = assetChangeRequest.placeholderForCreatedAsset
let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: self.assetCollection)
albumChangeRequest.addAssets([assetPlaceholder])
}, completionHandler: nil)
}
}
When you first instantiate the class, the custom album will be created if it doesn't already exist. You can save an image like this:
CustomPhotoAlbum.sharedInstance.saveImage(image)
NOTE: The CustomPhotoAlbum class assumes the app already has permission to access the Photo Library. Dealing with the permissions is a bit outside the scope of this question/answer. So make sure PHPhotoLibrary.authorizationStatus() == .Authorize before you use it. And request authorization if necessary.