-
Notifications
You must be signed in to change notification settings - Fork 266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AppSync, S3 and React Native (Expo) #183
Comments
I have succeeded in uploading my file, but associated dynamodb is not created |
In fact here is my schema
So I have a picture object with a file sub-object
which causes the following error: "GraphQL error: The variables input contains a field name 'bucket' that is not defined for input object type 'PictureInput' " because fileFieldKey is picture and it replaces picture with { bucket, key, region } (instead of file) |
There is a solution by splitting Picture and S3Object and having 2 variables in mutation instead of one. My current mutation is :
changing it in
|
Pull request made : #204 |
@mlecoq how did you exactly form the file object? I am trying to upload to S3 with react native without success for hours. I am providing bucket, region, key and localUri of my file that I retrieved from Image Picker. I get the document created in DynamoDB; however, I don't get the file uploaded to S3. |
In your schema, you have to define one of your mutation variables as {key, bucket, region}. On client side, you have to send this variable as {localUri, mimeType, key, bucket, region} : appsync sdk will use localUri and mimeType to upload the file to s3 bucket (and then will only send key, bucket and region infos to appsync endpoint) |
@mlabieniec I really feel like I'm going crazy now. It would be great if you can be kind enough to take a look at this just one more time. I have my inputs looking like below
I have a resolver that looks like below on createPost
I get this list inserted to my images column
The 'bucket', 'region' are correctly set to my bucket name and my bucket region of course. I think the only difference with your input and mine is whether the images are in array or a single object. If you have any suggestions to what might be going wrong, please tell me. Thank you very much! |
Array are not supported. In fact the sdk check if one of your mutation variables has the format {key, bucket ...} to upload files. So array are not viewed |
See #161 |
@mlecoq it is unbelievably still not working... document is created just fine with S3Object but no upload... I have no single idea why |
Put some logs in complex-object-link.js in node-modules/AWS-appsync/lib directory, especially in catch blocs to see which errors are raised |
As @mlecoq correctly pointed out, the SDK only uploads the file to S3 if all 5 keys are present:
I am working on adding unit tests for this logic (so you can see clearly what is expected in terms of variables), I'll reference this issue in the PR once ready. That same PR will probably add support for arrays (#161) |
@manueliglesias please have a look into #179 |
providing all above still doesn't work, entry is created but file is not uploaded |
Hi @mlecoq - it seems you have got the S3Object uploading successfully through the AppSync resolver to S3 and automatically storing the url as an item in the DynamoDB table? If so, I would really appreciate it if you could share your code with us. I am looking for an example of the react native client side uploading (my upload has an undefinded mimeType. Is this expected?). I see the mutation you are using, could you share your resolver? Also, is your S3 bucket public? I can not figure out how to authorize the cognito user other than using the docs ( complexObjectsCredentials: () => Auth.currentCredentials(),). Thanks in advance!! |
S3 bucket is not public, in fact I had to use federated identities (cognito only is not sufficient) to associate a role with grant access to bucket. The resolver : On appsync I does not receive the file but an object (with bucket, region and key):
|
Hey
Yes it did work the problem had nothing to do with da the resolver as a
matter of fact it most likely blob conversation if u r using react native
on the client side, if that is true for ur case "react native app" then
make sure u use blob data and yes I don't mind sharing code as soon as I
get my hand on keyboard
…On Tue, Dec 11, 2018, 7:35 PM Mickael Lecoq ***@***.***> wrote:
@mikeRChambers610 <https://github.com/mikeRChambers610>
S3 bucket is not public, in fact I had to use federated identities
(cognito only is not sufficient) to associate a role with grant access to
bucket. The resolver :
On appsync I does not receive the file but an object (with bucket, region
and key):
type File {
bucket: String!
region: String!
key: String!
}
input PictureInput {
bucket: String!
region: String!
key: String!
}
type Picture {
picture_id: String!
file: File
}
type Mutation {
addPicture(picture: PictureInput!): Picture
}
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#183 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ALajjzjZp4tAOjp4sSn7cflnEsokjYkoks5u397VgaJpZM4VRyp2>
.
|
Yes this is how it supposed 2 work no file but file key to retrieve later
…On Tue, Dec 11, 2018, 7:35 PM Mickael Lecoq ***@***.***> wrote:
@mikeRChambers610 <https://github.com/mikeRChambers610>
S3 bucket is not public, in fact I had to use federated identities
(cognito only is not sufficient) to associate a role with grant access to
bucket. The resolver :
On appsync I does not receive the file but an object (with bucket, region
and key):
type File {
bucket: String!
region: String!
key: String!
}
input PictureInput {
bucket: String!
region: String!
key: String!
}
type Picture {
picture_id: String!
file: File
}
type Mutation {
addPicture(picture: PictureInput!): Picture
}
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#183 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ALajjzjZp4tAOjp4sSn7cflnEsokjYkoks5u397VgaJpZM4VRyp2>
.
|
@mlecoq @motae99 Thank you for the responses. I appreciate all of the help that I can get. My react native app is using cognito user pools and has been working fine. For testing purposes my S3 bucket is public. Would you please review my configuration below and let me know where I might be going wrong? Thanks a lot! REACT NATIVE METHOD (No error but nothing happens on the backend) -- sendPicS3 = async () => { let file;
} REACT NATIVE GRAPHQL MUTATION -- import graphql from 'graphql-tag' export default graphql APPSYNC SCHEMA input CreateTestFileInput { type S3Object { input S3ObjectInput { APPSYNC MUTATION createTestFile(username: String!, file: S3ObjectInput!): TestFile APPSYNC RESOLVER {
} APPSYNC RESPONSE RESOLVER { $util.toJson($util.dynamodb.fromS3ObjectJson($context.source.file)) |
Something prevents file from upload using the SDK which accept blob type u
haven't shared this code which is most likely the reason, after file is
selected by the user u need to process it and convert it to blob if not by
default it all depends on the extension u using for file upload
I'll share my code with ya, it works just fine
…On Thu, Jan 3, 2019, 7:08 PM mikechambers610 ***@***.***> wrote:
@mlecoq <https://github.com/mlecoq> @motae99 <https://github.com/motae99>
Thank you for the responses. I appreciate all of the help that I can get.
My react native app is using cognito user pools and has been working fine.
For testing purposes my S3 bucket is public. Would you please review my
configuration below and let me know where I might be going wrong? Thanks a
lot!
REACT NATIVE METHOD (No error but nothing happens on the backend) --
sendPicS3 = async () => {
let file;
let uri = this.state.result;
if (uri) { // selectedFile is the file to be uploaded, typically comes from an <input type="file" />
const { name, type: mimeType } = uri;
const [, , , extension] = /([^.]+)(\.(\w+))?$/.exec(name);
const bucket = AWSConfig.aws_content_delivery_bucket;
const region = AWSConfig.aws_content_delivery_bucket_region;
const key = [uuidV4(), extension].filter(x => !!x).join('.');
file = {
bucket,
key,
region,
mimeType,
localUri: uri,
};
console.log(file)
this.props.onCreateTestFile({
username: this.state.username,
file: file,
})
}
}
REACT NATIVE GRAPHQL MUTATION --
import graphql from 'graphql-tag'
export default graphqlmutation CreateTestFile ($username: String!, $file:
S3ObjectInput!){ createTestFile( input: {username: $username, file: $file}
) { username file } }
APPSYNC SCHEMA
input CreateTestFileInput {
username: String!
file: S3ObjectInput!
}
type S3Object {
bucket: String!
region: String!
key: String!
}
input S3ObjectInput {
bucket: String!
region: String!
localUri: String
visibility: Visibility
key: String
mimeType: String
}
APPSYNC MUTATION
createTestFile(username: String!, file: S3ObjectInput!): TestFile
APPSYNC RESOLVER
{
"version": "2017-02-28",
"operation": "PutItem",
"key": {
"id": $util.dynamodb.toDynamoDBJson($ctx.args.input.username),
},
#set( $attribs = $util.dynamodb.toMapValues($ctx.args.input) )
#set( $file = $ctx.args.input.file )
#set( $attribs.file = $util.dynamodb.toS3Object($file.key, $file.bucket, $file.region) )
"attributeValues": $util.toJson($attribs)
}
APPSYNC RESPONSE RESOLVER
Request Resolver
{
"version": "2017-02-28",
"payload": {}
}
Response Resolver
$util.toJson($util.dynamodb.fromS3ObjectJson($context.source.file))
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#183 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ALajjy4kO02M1ImuI4_Q-3tBAFyxdQCIks5u_isJgaJpZM4VRyp2>
.
|
Thanks @motae99 I would appreciate if you could share your code that would help me a lot. |
@motae99 I am using the ImagePicker and storing the uri for the image selected in this.state.result. |
You need to pass your uri to .blob() to convert to blob data, like below
code
otherwise there are some extensions that do that for you automatically
if (selectedFile) {
const { fileName: fileName, type: mimeType } = selectedFile;
const [, , , extension] = /([^.]+)(\.(\w+))?$/.exec(fileName);
const key = `${visibility}/${identityId}/${uuid()}${extension && '.'}${
extension}`;
const imageData = await fetch(selectedFile.uri)
const blobData = await imageData.blob()
file = {
bucket,
key,
region,
mimeType,
localUri: blobData,
};
}
…On Thu, Jan 3, 2019 at 11:58 PM mikechambers610 ***@***.***> wrote:
@motae99 <https://github.com/motae99> I am using the ImagePicker and
storing the uri for the image selected in this.state.result.
After that I am storing this.state.result as "uri" and passing that
directly. I think that is probably the wrong way as you as saying it seems
like I need to be converting the file just not sure how to do that. Thanks!!
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#183 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ALajj97GT_EKaNeKOiZ-sVBdncqMnmaQks5u_n0BgaJpZM4VRyp2>
.
|
Thank you @motae99 . Do I need to import npm i react-native-fetch-blob ? Or is this .blob() a part of the JS and no imports needed for it? |
No you don't need 2
…On Mon, Jan 7, 2019, 6:51 PM mikeRChambers610 ***@***.***> wrote:
Thank you @motae99 <https://github.com/motae99> . Do I need to import npm
i react-native-fetch-blob ? Or is this .blob() a part of the JS and no
imports needed for it?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#183 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ALajjyhRFw8Mk72J4m_-WXU5o4R-5am-ks5vA20agaJpZM4VRyp2>
.
|
Hey U really don't need fileName to get it working only used to generate
meaningful key but u can just generate random unique key, it'd suffice,
* Generate ur key
* Make sure u have a mimetype
* Region and bucket of course
* Ur localuri in supported format in our case blob
If u ain't sure where does ur code break, I suggest u hardcoded on query
itself 2 confirm the desirable resault, then follow ur logs
Sharing ur error would help a lot
Leaving debug on for more insights
That's all I can say man hope it helps
…On Wed, Jan 9, 2019, 12:53 AM mikechambers610 ***@***.***> wrote:
Thanks @motae99 <https://github.com/motae99> & @mlecoq
<https://github.com/mlecoq> . I have created #335
<#335>
I am not sure what is missing from my project but have had no luck with
getting my S3Object working through Appsync from React-Native.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#183 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ALajj8bTNXtmQ8PkY8QSZBBlvT4O1AsIks5vBRNhgaJpZM4VRyp2>
.
|
In the code u shared ur mimetype is just type, stating the obvious
…On Thu, Jan 10, 2019, 5:57 PM Mohammed Taha ***@***.***> wrote:
Hey U really don't need fileName to get it working only used to generate
meaningful key but u can just generate random unique key, it'd suffice,
* Generate ur key
* Make sure u have a mimetype
* Region and bucket of course
* Ur localuri in supported format in our case blob
If u ain't sure where does ur code break, I suggest u hardcoded on query
itself 2 confirm the desirable resault, then follow ur logs
Sharing ur error would help a lot
Leaving debug on for more insights
That's all I can say man hope it helps
On Wed, Jan 9, 2019, 12:53 AM mikechambers610 ***@***.***>
wrote:
> Thanks @motae99 <https://github.com/motae99> & @mlecoq
> <https://github.com/mlecoq> . I have created #335
> <#335>
>
> I am not sure what is missing from my project but have had no luck with
> getting my S3Object working through Appsync from React-Native.
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <#183 (comment)>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/ALajj8bTNXtmQ8PkY8QSZBBlvT4O1AsIks5vBRNhgaJpZM4VRyp2>
> .
>
|
Hi - I was able to acheive my goal of uploading a picture to S3 and having a url to the S3 object in my dynamoDB. First I am sending the file to S3 via the NPM package 'react-native-aws3'. Once the file is uploaded to the bucket which I have used IAM to grant the cognito role permission, the url is returned as a promise. I then fire off a mutation to dynamodb to create an item in the table with the pic attribute as a String where I am storing the URL. Below code is working : sendPicS3 = async () => {
if (response.status !== 201) {
} } |
I struggled a lot in implementing file upload using Amplify, AppSync, and S3. Now reading all your answers and working on my own I thought it will be great to share my own solution. I am using Expo to access the library of the device, RNS3 to put the image in S3, and the AppSync SDK to execute the mutation that store the reference in DynamoDB. Here are screenshots of my entire code. Keys are from your IAM user. Second half of the AddPhoto.js I tried getting rid of RNS3 by using the Storage API to put the image in S3 (going fully Amplify), but the uploaded image is always broken. |
I'm trying to do a similar thing with Expo and react native and can't get the upload to S3 working correctly. I'm storing the photos in a const imageUri = `${FileSystem.documentDirectory}/photos/${filename}`; Then exactly as described above, I've got const imageData = await fetch(imageUri);
const blobData = await imageData.blob();
const variables = {
key: filename,
region: 'eu-west-2',
bucket: BUCKET_NAME,
mimeType: 'image/jpeg',
localUri: blobData
} And that's then passed to the mutation. Following its path through the debugger, it goes all the way through to the call in node_modules/aws-appsync/lib/link/complex-object-link-uploader.native.js line 19. Here the Body is of this form: {
_data: {
blobId: "5deabc19-2d0e-42f1-9e3c-1667f5a56e7e",
offset: 0,
size: 0,
type: "",
lastModified: 1552561833865
}
} What's surprising is if I test It feels like my very close, but I just can't see how to make it work... I've tried other approaches like turning it into base64 and putting the string in to localUri, but then the file stored in S3 simply has the base64 encoded version of the image, it doesn't decode it back to an image. What am I doing wrong? |
Check this component in my repo in here. I use Amplify Storage API to put and get images from S3. |
Hi @jtaylor1989, Thanks for the link. I tried putting your code into my project and it saves zero-length files, whereas if I run your code exactly as-is, yours works fine. So I think that maybe I'm importing something that is messing stuff up? Or I'm not including something I need? I notice, for example, that you've got |
I finally found the problem: for some reason in Expo:32, using Luckily, @yonahforst posted a solution here: expo/firebase-storage-upload-example#13 (comment) Basically I needed to get the blob in a different way, here's my version: const urlToBlob = (url: string) => {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.onerror = reject;
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
resolve(xhr.response);
}
};
xhr.open('GET', url);
xhr.responseType = 'blob'; // convert type
xhr.send();
});
}; Then my example above becomes: const blobData = await urlToBlob(imageUri);
const variables = {
key: filename,
region: 'eu-west-2',
bucket: BUCKET_NAME,
mimeType: 'image/jpeg',
localUri: blobData
} With that in place, the upload happens successfully and then the mutation works too. If anyone is wondering why their file isn't uploading, I recommend putting a breakpoint on line 60 or so of Thanks again @jtaylor1989 for giving me the clue I needed :-) |
Hi,
I do not succeed in uploading pictures on s3 on my react native app (see https://stackoverflow.com/questions/51366876/aws-appsync-cognito-s3)
I have tried many ways to put params for localUri ( {fileName, mimeType} like in https://github.com/aws-samples/aws-amplify-graphql, base64, file uri ...). There is no information in appsync logs to explain why file is not uploaded to s3 (whereas an entry is added in dynamodb table). Looking in redux inspector, I see commit_offline_mutation actions like if everything worked fine. File upload silently fails.
sdk should warn us when file upload is not possible.
It could help us to figure out which mistake has been made.
The text was updated successfully, but these errors were encountered: