* Which Category is your question related to? *
GraphQL AppSync, and S3 Uploads with Complex Objects.
* What AWS Services are you utilizing? *
GraphQL AppSync, and S3 Uploads with Complex Objects.
* Provide additional details e.g. code snippets *
I have set up a simple Blog, but each article will require a single Feature Image, so I set up my schema as follows...
enum Visibility {
public
private
}
type Post @model {
id: ID!
title: String!
content: String!
feature: S3Object
gallery: S3Object
comments: [Comment] @connection(name: "PostComments")
author: [Author] @connection(name: "PostAuthor")
}
type S3Object {
bucket: String!
key: String!
region: String!
localUri: String
mimeType: String
}
type Author @model {
id: ID!
username: String!
email: String!
post: Post @connection(name: "PostAuthor")
}
type Comment @model {
id: ID!
content: String
post: Post @connection(name: "PostComments")
}
input S3ObjectInput {
id: ID
name: String!
description: String
file: S3ObjectInput
}
I have read the articles about complex objects, but the mutation looks like it needs some extra structure that looks to be missing in the documentation.
if (this.props.currentMethod === 'add') {
await API.graphql(graphqlOperation(createPost, { input: this.state }))
.then(result => {
console.log(result);
this.props.onChangeMethod('listing');
})
.catch(err => console.log(err));
}
Thats my existing createPost mutation, without the S3 Upload added... this.state doesn't have the feature object yet... I need to add 'feature' to my state.
If I add feature as
feature = {
bucket,
key,
region,
localUri: selectedFile,
mimeType,
};
Where do I upload the file? Do I add feature to the mutation state, to send it up to AWS... Do I do the S3 Upload separately with something else, and just store the key and such locally?
Hi @michaelcuneo
I've noticed you are using Amplify's API category (await API.graphql(graphqlOperation(createPost, { input: this.state }))
).
The automatic upload of complex objects is a feature of the aws-appsync
package. The docs you looked at were probably for this package. You can look at this sample app for usage.
If you don't want to use the apollo based client (aws-appsync), you need to upload the file yourself using the Storage
category.
So I either have to wrap my app in Apollo and use the old way of auth, api setup, etc... or use a really really old, way of doing the upload myself and ignoring the fact that amplify-is is now an Apollo wrapper when using API GraphQL? This means it鈥檚 impossible.
Why would amplify-js wrap Apollo automatically, but disable most of its useful function like, ComplexObjects?
What I mean is... amplify-js does away with the complex writing your own queries and mutations and provides them in an easy automated setup, and wraps it all in Apollo, (If I remember correctly)... so to use Complex Objects I have to completely do away with amplify-js... how can I wrap apollo twice? How can I have a bunch of predesigned mutations and queries, and just start writing my own? It's as if this is half implemented? I'm entirely baffled...
Facing a similar issue. Is there a detailed example on how to achieve this in React Native using AppSync (i.e. uploading files to S3 with Amplify GraphQL Client and storing pointers to those files in DynamoDB).
I was made aware ages ago that amplify-cli was no longer being developed, and it was becoming amplify-js... but recently I've been looking at the git-hub for aws-amplify, and there's two now being developed side by side? What's the deal with that? Why would anyone still use amplify-cli if it's now called amplify-js, and what's the difference between the two. I remember Amplify-cli made a folder in my project that was very similar to amplify-js but called aws-amplify or something like that. For a while there though. there was a big warning on the old github that it wasn't being developed anymore and people should refer to amplify-js. I'm so damn confused.
I struggled a lot in implementing file upload using Amplify, AppSync, and S3 for my React native application.
As far as I understand, Amplify AppSync GraphQL Client does not support complex objects. You must use the AppSync SDK (with the Apollo Client) to achieve this.
I wanted to share with you my methodology on how I made it work. Probably this will give you some insights.
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.
Full repo in my Github.
Here are screenshots of my entire code. Keys are from your IAM user.
schema.graphql
MutationCreatePicture.js
App.js
First half of the AddPhoto.js
Second half of the AddPhoto.js
@dabit3 can you please comment.
Starting from this tutorial - https://github.com/aws-samples/aws-amplify-graphql
I have run into a similar requirement where I have to upload an image and do it while creating/updating an object (appsync + dynamo) as an atomic operation but the below just puts an entry into dynamo and _not_ upload to S3. Does amplify-js does _not_ have this capability to deal with complex objects ?
await API.graphql(graphqlOperation(createPicture,
{
input: {
name,
owner,
visibility,
id: uuid(),
createdAt: new Date().toISOString(),
file: { bucket,
region,
key,
localUri,
mimeType
}
}
}))
.then(res => {
console.log("Done");
});
Schema -
type Picture @model @auth(rules: [{allow: owner}]) {
id: ID!
name: String
owner: String
visibility: Visibility
file: S3ObjectInput
createdAt: String
}
type S3Object {
bucket: String!
region: String!
key: String!
localUri: String!
mimeType: String!
}
enum Visibility {
public
private
}
Am also having the same issue.. I should have probably choosen the AWS AppSync SDK to begin with, will have to go back and change things around...
Same issue here as well. You cannot upload images to S3 using aws amplify graphql client.
Must use the Appsync SDK which has a huge size just like every other AWS package, bloating your app. The documentation should make it clear that you cannot use complexobjects at the beginning so that people don't have to rewrite a significant portion of the app just because they used the graphql client.
馃憥
As mentioned above, the AppSync SDK supports complex objects. Here is the documentation.
@michaelcuneo, amplify-js and amplify-cli are both actively developed projects that help achieve different goals. Not sure where you read that amplify-cli was not being actively developed.
I will mark this as a feature request as this thread seems to be a request to add complex object support for the Amplify GraphQL client.
@jordanranz I made it working by defining the following types:
input S3ObjectInput {
bucket: String!
key: String!
region: String!
localUri: String
mimeType: String
}
type S3Object {
bucket: String!
key: String!
region: String!
}
And then:
type User
@model
@auth(
rules: [
{
allow: owner
ownerField: "id"
queries: [get]
mutations: [create, update]
}
]
) {
id: ID!
alias: String!
email: AWSEmail!
fullName: String!
phone: AWSPhone!
society: String!
avatar: S3Object
logo: S3Object
language: String
}
In front:
const { name, type: mimeType } = selectedFile;
const [, , , extension] = /([^.]+)(\.(\w+))?$/.exec(name);
const bucket = awsconfig.aws_user_files_s3_bucket;
const region = awsconfig.aws_user_files_s3_bucket_region;
const visibility = "public";
const { identityId } = await(this as any).$Amplify.Auth.currentCredentials();
const key = `${visibility}/${identityId}/${uuidv4()}${
extension && "."
}${extension}`;
const file = {
bucket,
key,
region,
mimeType,
localUri: selectedFile,
};
const userDoc = await(this as any).$Amplify.API.graphql(
(this as any).$Amplify.graphqlOperation(updateUser, {
input: {
id: this.stateUser.id,
logo: file,
},
})
) as GraphQLResult<UpdateUserMutation>;
console.log("userDoc", userDoc);
I just had to define S3ObjectInput
and S3Object
otherwise it doesn't work.
I think we can close this issue if the documentation is updated.
I tried doing the above but it didn't seem to work for me, no new images appear in my bucket. Did anyone else have luck with @mtltechtemp 's approach?
I gave up and just upload straight using Storage.put
and on top I get the progress update event:
export const upload = (file, onProgress) => {
const { type: mimeType } = file;
const target = uuid();
const key = `images/${target}`
return Storage.put(key, file, {
progressCallback: onProgress,
contentType: mimeType,
}).then(() => Promise.resolve({key, target}))
}
after that I just store the actual reference in dynamo.
Most helpful comment
Same issue here as well. You cannot upload images to S3 using aws amplify graphql client.
Must use the Appsync SDK which has a huge size just like every other AWS package, bloating your app. The documentation should make it clear that you cannot use complexobjects at the beginning so that people don't have to rewrite a significant portion of the app just because they used the graphql client.
馃憥