- Notifications
You must be signed in to change notification settings - Fork263
JavaScript library files for Offline, Sync, Sigv4. includes support for React Native
License
awslabs/aws-mobile-appsync-sdk-js
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
AWS AppSync is a fully managed service that makes it easy to develop GraphQL APIs by handling the heavy lifting of securely connecting to data sources like AWS DynamoDB, Lambda, and more.
You can use any HTTP or GraphQL client to connect to a GraphQL API on AppSync.
For front-end web and mobile development, we recommend using theAWS Amplify library which is optimized to connect to the AppSync backend.
- For DynamoDB data sources where conflict detection and resolution are enabled on AppSync, use theDataStore category in the Amplify library.
- For non-DynamoDB data sources in scenarios where you have no offline requirements, use theAPI (GraphQL) category in the Amplify library.
- If you want to use the Apollo V3 client, use the Apollo Links in this repository to help with authorization and subscriptions.
Looking for the AWS AppSync SDK for JavaScript (built on Apollo v2)? AWS AppSync SDK for JavaScript (V2) is now in Maintenance Mode until June 30th, 2024. This means that we will continue to include updates to ensure compatibility with backend services and security. No new features will be introduced in the AWS AppSync SDK for JavaScript (V2). Please review theupgrade guide for recommended next steps.
AWS AppSync Links for Apollo V3 (Maintenance mode)
If you would like to use theApollo JavaScript client version 3 to connect to your AppSync GraphQL API, this repository (on the current stable branch) provides Apollo links to use the different AppSync authorization modes, and to setup subscriptions over web sockets. Please log questions for this client SDK in this repo and questions for the AppSync service in theofficial AWS AppSync forum .
package | version |
---|---|
aws-appsync-auth-link | |
aws-appsync-subscription-link |
Example usage of Apollo V3 links
For more documentation ongraphql
operations performed by React Apollo see theirdocumentation.
For versions of the Apollo client newer than 2.4.6 you can use custom links for Authorization and Subscriptions. Offline support is not available for these newer versions. The packages available areaws-appsync-auth-link
andaws-appsync-subscription-link
. Below is a sample code snippet that shows how to use it.
import{createAuthLink}from"aws-appsync-auth-link";import{createSubscriptionHandshakeLink}from"aws-appsync-subscription-link";import{ApolloProvider,ApolloClient,InMemoryCache,HttpLink,ApolloLink,}from"@apollo/client";importappSyncConfigfrom"./aws-exports";/* The HTTPS endpoint of the AWS AppSync API(e.g. *https://aaaaaaaaaaaaaaaaaaaaaaaaaa.appsync-api.us-east-1.amazonaws.com/graphql*).[Custom domain names](https://docs.aws.amazon.com/appsync/latest/devguide/custom-domain-name.html) can also be supplied here (e.g. *https://api.yourdomain.com/graphql*).Custom domain names can have any format, but must end with `/graphql`(see https://graphql.org/learn/serving-over-http/#uris-routes). */consturl=appSyncConfig.aws_appsync_graphqlEndpoint;constregion=appSyncConfig.aws_appsync_region;constauth={type:appSyncConfig.aws_appsync_authenticationType,apiKey:appSyncConfig.aws_appsync_apiKey,// jwtToken: async () => token, // Required when you use Cognito UserPools OR OpenID Connect. token object is obtained previously// credentials: async () => credentials, // Required when you use IAM-based auth.};consthttpLink=newHttpLink({uri:url});constlink=ApolloLink.from([createAuthLink({ url, region, auth}),createSubscriptionHandshakeLink({ url, region, auth},httpLink),]);constclient=newApolloClient({ link,cache:newInMemoryCache(),});constApolloWrapper=({ children})=>{return<ApolloProviderclient={client}>{children}</ApolloProvider>;};
importReact,{useState,useEffect}from"react";import{gql,useSubscription}from"@apollo/client";import{useMutation,useQuery}from"@apollo/client";import{v4asuuidv4}from"uuid";constinitialState={name:"",description:""};constApp=()=>{constLIST_TODOS=gql` query listTodos { listTodos { items { id name description } } } `;const{loading:listLoading,data:listData,error:listError,}=useQuery(LIST_TODOS);constCREATE_TODO=gql` mutation createTodo($input: CreateTodoInput!) { createTodo(input: $input) { id name description } } `;// https://www.apollographql.com/docs/react/data/mutations/const[addTodoMutateFunction,{error:createError}]=useMutation(CREATE_TODO);asyncfunctionaddTodo(){try{addTodoMutateFunction({variables:{input:{ todo}}});}catch(err){console.log("error creating todo:",err);}}constDELETE_TODO=gql` mutation deleteTodo($input: DeleteTodoInput!) { deleteTodo(input: $input) { id name description } } `;const[deleteTodoMutateFunction]=useMutation(DELETE_TODO,{refetchQueries:[LIST_TODOS,"listTodos"],});asyncfunctionremoveTodo(id){try{deleteTodoMutateFunction({variables:{input:{ id}}});}catch(err){console.log("error deleting todo:",err);}}constCREATE_TODO_SUBSCRIPTION=gql` subscription OnCreateTodo { onCreateTodo { id name description } } `;const{data:createSubData,error:createSubError}=useSubscription(CREATE_TODO_SUBSCRIPTION);return(// Render TODOs);};exportdefaultApp;
AWS AppSync JavaScript SDK based on Apollo V2 (Maintenance mode)
Theaws-appsync
andaws-appsync-react
packages work with theApollo client version 2 and provide offline capabilities.
Note: if you do not have any offline requirements in your app, we recommend using theAmplify libraries.
package | version |
---|---|
aws-appsync | |
aws-appsync-react |
npm install --save aws-appsync
yarn add aws-appsync
When using this library with React Native, you need to ensure you are using the correct version of the library based on your version of React Native. Take a look at the table below to determine what version to use.
aws-appsync version | Required React Native Version |
---|---|
2.x.x | >= 0.60 |
1.x.x | <= 0.59 |
If you are using React Native0.60
and above, you also need to install@react-native-community/netinfo
and@react-native-community/async-storage
:
npm install --save @react-native-community/netinfo@5.9.4 @react-native-community/async-storage
or
yarn add @react-native-community/netinfo@5.9.4 @react-native-community/async-storage
If you are using React Native0.60+
for iOS, run the following command as an additional step:
npx pod-install
importAWSAppSyncClientfrom"aws-appsync";importAppSyncConfigfrom"./aws-exports";import{ApolloProvider}from"react-apollo";import{Rehydrated}from"aws-appsync-react";// this needs to also be installed when working with ReactimportAppfrom"./App";constclient=newAWSAppSyncClient({/* The HTTPS endpoint of the AWS AppSync API (e.g. *https://aaaaaaaaaaaaaaaaaaaaaaaaaa.appsync-api.us-east-1.amazonaws.com/graphql*). [Custom domain names](https://docs.aws.amazon.com/appsync/latest/devguide/custom-domain-name.html) can also be supplied here (e.g. *https://api.yourdomain.com/graphql*). Custom domain names can have any format, but must end with `/graphql` (see https://graphql.org/learn/serving-over-http/#uris-routes). */url:AppSyncConfig.aws_appsync_graphqlEndpoint,region:AppSyncConfig.aws_appsync_region,auth:{type:AppSyncConfig.aws_appsync_authenticationType,apiKey:AppSyncConfig.aws_appsync_apiKey,// jwtToken: async () => token, // Required when you use Cognito UserPools OR OpenID Connect. Token object is obtained previously// credentials: async () => credentials, // Required when you use IAM-based auth.},});constWithProvider=()=>(<ApolloProviderclient={client}><Rehydrated><App/></Rehydrated></ApolloProvider>);exportdefaultWithProvider;
importgqlfrom"graphql-tag";import{graphql}from"react-apollo";constlistPosts=gql` query listPosts { listPosts { items { id name } } }`;classAppextendsComponent{render(){return(<div>{this.props.posts.map((post,index)=>(<h2key={post.id ?post.id :index}>{post.name}</h2>))}</div>);}}exportdefaultgraphql(listPosts,{options:{fetchPolicy:"cache-and-network",},props:(props)=>({posts:props.data.listPosts ?props.data.listPosts.items :[],}),})(App);
importgqlfrom"graphql-tag";import{graphql,compose}from"react-apollo";import{graphqlMutation}from"aws-appsync-react";constCreatePost=gql` mutation createPost($name: String!) { createPost(input: { name: $name }) { name } }`;classAppextendsComponent{state={name:""};onChange=(e)=>{this.setState({name:e.target.value});};addTodo=()=>this.props.createPost({name:this.state.name});render(){return(<div><inputonChange={this.onChange}placeholder="Todo name"/><buttononClick={this.addTodo}>Add Todo</button>{this.props.posts.map((post,index)=>(<h2key={post.id ?post.id :index}>{post.name}</h2>))}</div>);}}exportdefaultcompose(graphql(listPosts,{options:{fetchPolicy:"cache-and-network",},props:(props)=>({posts:props.data.listPosts ?props.data.listPosts.items :[],}),}),graphqlMutation(CreatePost,listPosts,"Post"))(App);
importgqlfrom"graphql-tag";importuuidV4from"uuid/v4";import{graphql,compose}from"react-apollo";constCreatePost=gql` mutation createPost($name: String!) { createPost(input: { name: $name }) { name } }`;classAppextendsComponent{state={name:""};onChange=(e)=>{this.setState({name:e.target.value});};addTodo=()=>this.props.onAdd({id:uuidV4(),name:this.state.name});render(){return(<div><inputonChange={this.onChange}placeholder="Todo name"/><buttononClick={this.addTodo}>Add Todo</button>{this.props.posts.map((post,index)=>(<h2key={post.id ?post.id :index}>{post.name}</h2>))}</div>);}}exportdefaultcompose(graphql(listPosts,{options:{fetchPolicy:"cache-and-network",},props:(props)=>({posts:props.data.listPosts ?props.data.listPosts.items :[],}),}),graphql(CreatePost,{options:{update:(dataProxy,{data:{ createPost}})=>{constquery=listPosts;constdata=dataProxy.readQuery({ query});data.listPosts.items.push(createPost);dataProxy.writeQuery({ query, data});},},props:(props)=>({onAdd:(post)=>{props.mutate({variables:post,optimisticResponse:()=>({createPost:{ ...post,__typename:"Post"},}),});},}),}))(App);
importgqlfrom"graphql-tag";import{graphql}from"react-apollo";import{buildSubscription}from"aws-appsync";constlistPosts=gql` query listPosts { listPosts { items { id name } } }`;constPostSubscription=gql` subscription postSubscription { onCreatePost { id name } }`;classAppextendsReact.Component{componentDidMount(){this.props.data.subscribeToMore(buildSubscription(PostSubscription,listPosts));}render(){return(<div>{this.props.posts.map((post,index)=>(<h2key={post.id ?post.id :index}>{post.name}</h2>))}</div>);}}exportdefaultgraphql(listPosts,{options:{fetchPolicy:"cache-and-network",},props:(props)=>({posts:props.data.listPosts ?props.data.listPosts.items :[],data:props.data,}),})(App);
importgqlfrom"graphql-tag";import{graphql}from"react-apollo";constlistPosts=gql` query listPosts { listPosts { items { id name } } }`;constPostSubscription=gql` subscription postSubscription { onCreatePost { id name } }`;classAppextendsReact.Component{componentDidMount(){this.props.subscribeToNewPosts();}render(){return(<div>{this.props.posts.map((post,index)=>(<h2key={post.id ?post.id :index}>{post.name}</h2>))}</div>);}}exportdefaultgraphql(listPosts,{options:{fetchPolicy:"cache-and-network",},props:(props)=>({posts:props.data.listPosts ?props.data.listPosts.items :[],subscribeToNewPosts:(params)=>{props.data.subscribeToMore({document:PostSubscription,updateQuery:(prev,{subscriptionData:{data:{ onCreatePost},},})=>({ ...prev,listPosts:{__typename:"PostConnection",items:[onCreatePost, ...prev.listPosts.items.filter((post)=>post.id!==onCreatePost.id),],},}),});},}),})(App);
Many times you might want to create logical objects that have more complex data, such as images or videos, as part of their structure. For example, you might create a Person type with a profile picture or a Post type that has an associated image. With AWS AppSync, you can model these as GraphQL types, referred to as complex objects. If any of your mutations have a variable with bucket, key, region, mimeType and localUri fields, the SDK uploads the file to Amazon S3 for you.
For a complete working example of this feature, seeaws-amplify-graphql on GitHub.
If you're using AWS Amplify's GraphQL transformer, then configure your resolvers to write to DynamoDB and point at S3 objects when using theS3Object
type. For example, run the following in an Amplify project:
amplify add auth#Select default configurationamplify add storage#Select S3 with read/write accessamplify add api#Select Cognito User Pool for authorization type
When prompted, use the following schema:
typeTodo@model {id:ID!name:String!description:String!file:S3Object}typeS3Object {bucket:String!key:String!region:String!}inputCreateTodoInput {id:IDname:String!description:Stringfile:S3ObjectInput # This input type will be generated for you}
Save and runamplify push
to deploy changes.
To use complex objects you need AWS Identity and Access Management credentials for reading and writing to Amazon S3 whichamplify add auth
configures in the default setting along with a Cognito user pool. These can be separate from the other auth credentials you use in your AWS AppSync client. Credentials for complex objects are set using thecomplexObjectsCredentials
parameter, which you can use with AWS Amplify and the complex objects feature like so:
constclient=newAWSAppSyncClient({url:ENDPOINT,region:REGION,auth:{ ...},//Can be User Pools or API KeycomplexObjectsCredentials:()=>Auth.currentCredentials(),});(async()=>{letfile;if(selectedFile){// selectedFile is the file to be uploaded, typically comes from an <input type="file" />const{ name,type:mimeType}=selectedFile;const[,,,extension]=/([^.]+)(\.(\w+))?$/.exec(name);constbucket=aws_config.aws_user_files_s3_bucket;constregion=aws_config.aws_user_files_s3_bucket_region;constvisibility='private';const{ identityId}=awaitAuth.currentCredentials();constkey=`${visibility}/${identityId}/${uuid()}${extension&&'.'}${extension}`;file={ bucket, key, region, mimeType,localUri:selectedFile,};}constresult=awaitclient.mutate({mutation:gql(createTodo),variables:{input:{name:'Upload file',description:'Uses complex objects to upload',file:file,}}});})();
When you run the above mutation, a record will be in a DynamoDB table for your AppSync API as well as the corresponding file in an S3 bucket.
When using the AWS AppSync SDK offline capabilities (e.g.disableOffline: false
), you can provide configurations for the following:
- Error handling
- Custom storage engine
If a mutation is done while the app was offline, it gets persisted to the platform storage engine. When coming back online, it is sent to the GraphQL endpoint. When a response is returned by the API, the SDK will notify you of the success or error using the callback provided in theofflineConfig
param as follows:
constclient=newAWSAppSyncClient({url:appSyncConfig.graphqlEndpoint,region:appSyncConfig.region,auth:{type:appSyncConfig.authenticationType,apiKey:appSyncConfig.apiKey,},offlineConfig:{callback:(err,succ)=>{if(err){const{ mutation, variables}=err;console.warn(`ERROR for${mutation}`,err);}else{const{ mutation, variables}=succ;console.info(`SUCCESS for${mutation}`,succ);}},},});
You can use any custom storage engine from theredux-persist supported engines list.
Configuration is done as follows: (localForage shown in the example)
import*aslocalForagefrom"localforage";constclient=newAWSAppSyncClient({url:appSyncConfig.graphqlEndpoint,region:appSyncConfig.region,auth:{type:appSyncConfig.authenticationType,apiKey:appSyncConfig.apiKey,},offlineConfig:{storage:localForage,},});
For detailed documentation about the offline helpers, look at theAPI Definition.
For more documentation on Vue Apollo clickhere.
importVuefrom"vue";importAppfrom"./App";importrouterfrom"./router";importAWSAppSyncClientfrom"aws-appsync";importVueApollofrom"vue-apollo";importAppSyncConfigfrom"./aws-exports";constconfig={url:AppSyncConfig.graphqlEndpoint,region:AppSyncConfig.region,auth:{type:AppSyncConfig.authType,apiKey:AppSyncConfig.apiKey,},};constoptions={defaultOptions:{watchQuery:{fetchPolicy:"cache-and-network",},},};constclient=newAWSAppSyncClient(config,options);constappsyncProvider=newVueApollo({defaultClient:client,});Vue.use(VueApollo);newVue({el:"#app", router,components:{ App},provide:appsyncProvider.provide(),template:"<App/>",});
<template><divid="app"v-if="hydrated"><router-view/></div></template><script>exportdefault{name:'App',data:()=>({hydrated:false}),asyncmounted(){awaitthis.$apollo.provider.defaultClient.hydrated()this.hydrated=true},}</script>
importgqlfrom"graphql-tag";importuuidV4from"uuid/v4";constCreateTask=gql` mutation createTask($id: ID!, $name: String!, $completed: Boolean!) { createTask(input: { id: $id, name: $name, completed: $completed }) { id name completed } }`;constDeleteTask=gql` mutation deleteTask($id: ID!) { deleteTask(input: { id: $id }) { id } }`;constListTasks=gql` query listTasks { listTasks { items { id name completed } } }`;constUpdateTask=gql` mutation updateTask($id: ID!, $name: String!, $completed: Boolean!) { updateTask(input: { id: $id, name: $name, completed: $completed }) { id name completed } }`;// In your component (Examples of queries & mutations)exportdefault{name:"Tasks",methods:{toggleComplete(task){constupdatedTask={ ...task,completed:!task.completed,};this.$apollo.mutate({mutation:UpdateTask,variables:updatedTask,update:(store,{data:{ updateTask}})=>{constdata=store.readQuery({query:ListTasks});constindex=data.listTasks.items.findIndex((item)=>item.id===updateTask.id);data.listTasks.items[index]=updateTask;store.writeQuery({query:ListTasks, data});},optimisticResponse:{__typename:"Mutation",updateTask:{__typename:"Task", ...updatedTask,},},}).then((data)=>console.log(data)).catch((error)=>console.error(error));},deleteTask(task){this.$apollo.mutate({mutation:DeleteTask,variables:{id:task.id,},update:(store,{data:{ deleteTask}})=>{constdata=store.readQuery({query:ListTasks});data.listTasks.items=data.listTasks.items.filter((task)=>task.id!==deleteTask.id);store.writeQuery({query:ListTasks, data});},optimisticResponse:{__typename:"Mutation",deleteTask:{__typename:"Task", ...task,},},}).then((data)=>console.log(data)).catch((error)=>console.error(error));},createTask(){consttaskname=this.taskname;if(taskname===""){alert("please create a task");return;}this.taskname="";constid=uuidV4();consttask={name:taskname, id,completed:false,};this.$apollo.mutate({mutation:CreateTask,variables:task,update:(store,{data:{ createTask}})=>{constdata=store.readQuery({query:ListTasks});data.listTasks.items.push(createTask);store.writeQuery({query:ListTasks, data});},optimisticResponse:{__typename:"Mutation",createTask:{__typename:"Task", ...task,},},}).then((data)=>console.log(data)).catch((error)=>console.error("error!!!: ",error));},},data(){return{taskname:"",tasks:[],};},apollo:{tasks:{query:()=>ListTasks,update:(data)=>data.listTasks.items,},},};
To create a new AppSync project, go tohttps://aws.amazon.com/appsync/.
This library is licensed under the Apache License 2.0.
About
JavaScript library files for Offline, Sync, Sigv4. includes support for React Native
Topics
Resources
License
Code of conduct
Contributing
Security policy
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.