26

Use AWS GraphQL for React Native Message App without Components

 5 years ago
source link: https://www.tuicool.com/articles/hit/ruQB3qA
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Recently I came up with a react native app which needs to integrate AWS GraphQL. Its actually provided with AWS App Sync and a very convenient way if you want a quick pub-sub. The problem was I had to do mutations as a background asynchronous process and wanted to update the app state from that. When I went through the documents I found the AWSAppSyncClient which is an Apollo Client. Although it was promising the react native examples were more focusing towards react or react-native Components which was really making a mess.

  1. The Views will have the logic of mutations and even if we move the code it wont be compact and easy to read.
  2. No way to call mutations asynchronously and since the state is maintained with redux, using component state for data is not good.

So I went through all the docs and used the Apollo Client documentation to come up with a plan like following

Configure AWSAppSyncClient to access AWS GraphQL URL

import AWSAppSyncClient from "aws-appsync";
import { Rehydrated } from 'aws-appsync-react';
import { AUTH_TYPE } from "aws-appsync/lib/link/auth-link";
import { graphql, ApolloProvider, compose } from 'react-apollo';

const client = new AWSAppSyncClient({
  url: amplifyConfig.API.graphqlEndpoint, // https://##################.appsync-api.##-####-#.amazonaws.com/graphql
  region: amplifyConfig.API.region,   // us-east-#
  auth: { 
    type: AUTH_TYPE.API_KEY,
    apiKey: amplifyConfig.API.apiKey,  //da2-##############
  },
  disableOffline: true,
});

Here I have used the API_KEY authentication since its easy for the first time configuration. Note that this auth key is expired after 7 days. Check the source code for the AWSAppSyncClient from the source https://github.com/awslabs/aws-mobile-appsync-sdk-js

The AWSAppSyncClient is a wrapper around the Apollo Client which is widely used as a Graphql client. The source for it can be found here https://github.com/awslabs/aws-mobile-appsync-sdk-js/blob/master/packages/aws-appsync/src/client.ts in case you need some understanding.

And the api reference regarding the Apollo Client can be found here https://www.apollographql.com/docs/react/api/apollo-client.html

Create a schema on AWS GraphQL, AWS App Sync

Login to the AppSync of AWS and create the schema with type message. (Note that you can change the data types as you want. I just wanted to use String here)

type Message {
  id: String!
  message: String!
  createdTime: String!
  createdUser: String!
}

qYjiai2.png!web

Then click on the Create Resource

VrA7niR.png!web

After that enter the details as in the image and create the data resource. It will create the DynamoDB table and resolvers to get the data. That way it’s a one-click creation. But you will often need to change the fields and queries to get the data that you require.

jErQNb7.png!web

InUbuiM.png!web

After creating the resource you will see the following schema.

input CreateMessageInput {
  id: String!
  message: String!
  createdTime: Int!
  createdUser: String!
}

input CreatePositionInput {
  userId: String!
  placeId: String!
  updatedTime: String!
}

input DeleteMessageInput {
  id: String!
  createdUser: String!
}

input DeletePositionInput {
  userId: String!
}
type Message {
  id: String!
  message: String!
  createdTime: Int!
  createdUser: String!
}

type MessageConnection {
  items: [Message]
  nextToken: String
}

type Mutation {
  createMessage(input: CreateMessageInput!): Message
  updateMessage(input: UpdateMessageInput!): Message
  deleteMessage(input: DeleteMessageInput!): Message
}

type Query {
        getMessage(id: String!, createdUser: String!): Message
  listMessages(first: Int, after: String): MessageConnection
}

type Subscription {
  onCreateMessage(
    id: String,
    message: String,
    createdTime: Int,
    createdUser: String
  ): Message
    @aws_subscribe(mutations: ["createMessage"])
  onUpdateMessage(
    id: String,
    message: String,
    createdTime: Int,
    createdUser: String
  ): Message
    @aws_subscribe(mutations: ["updateMessage"])
  onDeleteMessage(
    id: String,
    message: String,
    createdTime: Int,
    createdUser: String
  ): Message
    @aws_subscribe(mutations: ["deleteMessage"])
}

schema {
  query: Query
  mutation: Mutation
  subscription: Subscription
}

Then save the schema and let’s code schema for the client to send message data

Query for schema from Client

Now we have to create the client schema. For that first what we need is a create mutation. And then subscribe to new messages created. The createMessage mutation schema looks like follows. And I have used this as Message.schema.js  in next Message service

export const CreatePosition = gql`mutation CreateMessage($id: String!, $message: String!, $createdTime: String!, $createdUser: String!) {
  createMessage(input: {id: $id, message: $message, createdTime: $createdTime, createdUser: $createdUser }) {
   id
   message
   createdTime
   createdUser
  }
}`;


export const SubscribeToMessage = gql`subscription OnUpdateMessage($createdUser: String!) {
 onUpdateMessage(createdUser: $createdUser) {
   id
   message
   createdTime
   createdUser
 }
}`;

Create an object that could execute this query using apollo client as follows. I named it as Message.subscription.js

import gql from 'graphql-tag';
import { CreateMessage, SubscribeToMessage } from './schema/Message.schema';

export class MessageSubscription {

  constructor() {
    this.initialized = false;
  }

  init({ store, client }) {
    this.store = store;
    this.client = client;
    this.initialized = true;
  }

  checkInitialized() {
    if (!this.initialized) {
      throw "Subscription Not initialized";
    }
  }

  createMessage(message) {
    const result = client.mutate({
      mutation: CreateMessage,
      variables: message,
    }).then(result => {
      store.dispatch(Actions.messageCreated(result))
    }).catch(e => {
        // check and retry for attempts or send an error message
    });
  }

  subscribeToMessages(userId, force = false) {
    if (userId === this.userId && !force) {
      return;
    }

    const { dispatch } = this.store;
      client.subscribe({ query: SubscribeToMessage, variables: {
        createdUser: userId,
      }}).subscribe({
          next: (data) => {
            dispatch(Actions.messageRecieved(data));
          },
          //complete: subscribe again or notify
          //error: console.log,
        });
  }
}

export default new MessageSubscription();

Now your client service is ready. To integrate it with the app, initialize the service when creating the store

MessageSubscription.init({ store, client });

Now you can dispatch any action and invoke the create Message and subscription as you want. Whether you want to access it through react components or redux actions with redux state.

The important thing to remember is that you need to consider the primary key and Validation errors which could occur with DynamoDB.

Feel free to add any comment if you want code or any other clarfications.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK