Brooke  Giles

Brooke Giles

1560841325

An introduction GraphQL with AWS AppSync

In this tutorial, we’ll learn how to take advantage of AWS AppSync, a managed GraphQL service, to build a full-stack application without writing a single line of back-end code.

GraphQL is becoming increasingly popular. The problem is that if you are a front-end developer, you are only half of the way there. GraphQL is not just a client technology. The server also has to be implemented according to the specification. This means that in order to implement GraphQL into your application, you need to learn not only GraphQL on the front end, but also GraphQL best practices, server-side development, and everything that goes along with it on the back end.

There will come a time when you will also have to deal with issues like scaling your server, complex authorization scenarios, malicious queries, and more issues that require more expertise and even deeper knowledge around what is traditionally categorized as back-end development.

Thankfully, we have an array of managed back-end service providers today that allow front-end developers to only worry about implementing features on the front end without having to deal with all of the traditional back-end work.

Services like Firebase (API) / AWS AppSync (database), Cloudinary (media), Algolia (search) and Auth0 (authentication) allow us to offload our complex infrastructure to a third-party provider and instead focus on delivering value to end users in the form of new features instead.

In this tutorial, we’ll learn how to take advantage of AWS AppSync, a managed GraphQL service, to build a full-stack application without writing a single line of back-end code.

While the framework we’re working in is React, the concepts and API calls we will be using are framework-agnostic and will work the same in Angular, Vue, React Native, Ionic or any other JavaScript framework or application.

We will be building a restaurant review app. In this app, we will be able to create a restaurant, view restaurants, create a review for a restaurant, and view reviews for a restaurant.

The tools and frameworks that we will be using are React, AWS Amplify, and AWS AppSync.

AWS Amplify is a framework that allows us to create and connect to cloud services, like authentication, GraphQL APIs, and Lambda functions, among other things. AWS AppSync is a managed GraphQL service.

We’ll use Amplify to create and connect to an AppSync API, then write the client side React code to interact with the API.

View Repo

Getting started

The first thing we’ll do is create a React project and move into the new directory:

npx create-react-app ReactRestaurants

cd ReactRestaurants

Next, we’ll install the dependencies we’ll be using for this project. AWS Amplify is the JavaScript library we’ll be using to connect to the API, and we’ll use Glamor for styling.

yarn add aws-amplify glamor

The next thing we need to do to is install and configure the Amplify CLI:

npm install -g @aws-amplify/cli

amplify configure

Amplify’s configure will walk you through the steps needed to begin creating AWS services in your account. For a walkthrough of how to do this, check out this video.

Now that the app has been created and Amplify is ready to go, we can initialize a new Amplify project.

amplify init

Amplify init will walk you through the steps to initialize a new Amplify project. It will prompt you for your desired project name, environment name, and text editor of choice. The CLI will auto-detect your React environment and select smart defaults for the rest of the options.

Creating the GraphQL API

One we’ve initialized a new Amplify project, we can now add the Restaurant Review GraphQL API. To add a new service, we can run the amplify add command.

amplify add api

This will walk us through the following steps to help us set up the API:

? Please select from one of the below mentioned services GraphQL
? Provide API name bigeats
? Choose an authorization type for the API API key
? Do you have an annotated GraphQL schema? N
? Do you want a guided schema creation? Y
? What best describes your project: Single object with fields
? Do you want to edit the schema now? Y

The CLI should now open a basic schema in the text editor. This is going to be the schema for our GraphQL API.

Paste the following schema and save it.

// amplify/backend/api/bigeats/schema.graphql

type Restaurant @model {
  id: ID!
  city: String!
  name: String!
  numRatings: Int
  photo: String!
  reviews: [Review] @connection(name: "RestaurantReview")
}
type Review @model {
  rating: Int!
  text: String!
  createdAt: String
  restaurant: Restaurant! @connection(name: "RestaurantReview")
}

In this schema, we’re creating two main types: Restaurant and Review. Notice that we have @model and @connection directives in our schema.

These directives are part of the GraphQL Transform tool built into the Amplify CLI. GraphQL Transform will take a base schema decorated with directives and transform our code into a fully functional API that implements the base data model.

If we were spinning up our own GraphQL API, then we’d have to do all of this manually:

  1. Define the schema
  2. Define the operations against the schema (queries, mutations, and subscriptions)
  3. Create the data sources
  4. Write resolvers that map between the schema operations and the data sources.

With the @model directive, the GraphQL Transform tool will scaffold out all schema operations, resolvers, and data sources so all we have to do is define the base schema (step 1). The @connection directive will let us model relationships between the models and scaffold out the appropriate resolvers for the relationships.

In our schema, we use @connection to define a relationship between Restaurant and Reviews. This will create a unique identifier for the restaurant ID for the review in the final generated schema.

Now that we’ve created our base schema, we can create the API in our account.

amplify push
? Are you sure you want to continue? Yes
? Do you want to generate code for your newly created GraphQL API Yes
? Choose the code generation language target javascript
? Enter the file name pattern of graphql queries, mutations and subscriptions src/graphql/**/*.js
? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions Yes

Because we’re creating a GraphQL application, we typically would need to write all of our local GraphQL queries, mutations and subscriptions from scratch. Instead, the CLI will be inspecting our GraphQL schema and then generating all of the definitions for us and saving them locally for us to use.

After this is complete, the back end has been created and we can begin accessing it from our React application.

If you’d like to view your AppSync API in the AWS dashboard, visit https://console.aws.amazon.com/appsync and click on your API. From the dashboard you can view the schema, data sources, and resolvers. You can also perform queries and mutations using the built-in GraphQL editor.

Building the React client

Now that the API is created and we can begin querying for and creating data in our API. There will be three operations we will be using to interact with our API:

  1. Define the schema
  2. Define the operations against the schema (queries, mutations, and subscriptions)
  3. Create the data sources
  4. Write resolvers that map between the schema operations and the data sources.

Before we start building the app, let’s take a look at how these operations will look and work.

Interacting with the AppSync GraphQL API

When working with a GraphQL API, there are many GraphQL clients available.

We can use any GraphQL client we’d would like to interact with an AppSync GraphQL API, but there are two that are configured specifically to work most easily. These are the Amplify client (what we will use) and the AWS AppSync JS SDK (similar API to Apollo client).

The Amplify client is similar to the fetch API in that it is promise-based and easy to reason about. The Amplify client does not support offline out of the box. The AppSync SDK is more complex but does support offline out of the box.

To call the AppSync API with Amplify, we use the API category. Here’s an example of how to call a query:

import { API, graphqlOperation } from 'aws-amplify'
import * as queries from './graphql/queries'

const data = await API.graphql(graphqlOperation(queries.listRestaurants))

For a mutation, it is very similar. The only difference is we need to pass in a a second argument for the data we are sending in the mutation:

import { API, graphqlOperation } from 'aws-amplify'
import * as mutations from './graphql/mutations'

const restaurant = { name: "Babalu", city: "Jackson" }
const data = await API.graphql(graphqlOperation(
  mutations.createRestaurant,
  { input: restaurant }
))

We use the graphql method from the API category to call the operation, wrapping it in graphqlOperation, which parses GraphQL query strings into the standard GraphQL AST.

We’ll be using this API category for all of our GraphQL operation in the app.

Here is the repo containing the final code for this project.

Configuring the React app with Amplify

The first thing we need to do in our app is configure it to recognize our Amplify credentials. When we created our API, the CLI created a new file called aws-exports.js in our src folder.

This file is created and updated for us by the CLI as we create, update and delete services. This file is what we’ll be using to configure the React application to know about our services.

To configure the app, open up src/index.js and add the following code:

import Amplify from 'aws-amplify'
import config from './aws-exports'
Amplify.configure(config)

Next, we will create the files we will need for our components. In the src directory, create the following files:

  • Header.js
  • Restaurant.js
  • Review.js
  • CreateRestaurant.js
  • CreateReview.js

Creating the components

While the styles are referenced in the code snippets below, the style definitions have been omitted to make the snippets less verbose. For style definitions, see the final project repo.

Next, we’ll create the Header component by updating [src/Header.js](https://github.com/dabit3/bigeats/blob/master/src/Header.js "src/Header.js").

// src/Header.js

import React from 'react'
import { css } from 'glamor'
const Header = ({ showCreateRestaurant }) => (
  <div {...css(styles.header)}>
    <p {...css(styles.title)}>BigEats</p>
    <div {...css(styles.iconContainer)}>
      <p {...css(styles.icon)} onClick={showCreateRestaurant}>+</p>
    </div>
  </div>
)

export default Header

Now that our Header is created, we’ll update [src/App.js](https://github.com/dabit3/bigeats/blob/master/src/App.js "src/App.js"). This file will hold all of the interactions with the API, so it is pretty large. We’ll define the methods and pass them down as props to the components that will call them.

// src/App.js

import React, { Component } from 'react'
import { API, graphqlOperation } from 'aws-amplify'

import Header from './Header'
import Restaurants from './Restaurants'
import CreateRestaurant from './CreateRestaurant'
import CreateReview from './CreateReview'
import Reviews from './Reviews'
import * as queries from './graphql/queries'
import * as mutations from './graphql/mutations'

class App extends Component {
  state = {
    restaurants: [],
    selectedRestaurant: {},
    showCreateRestaurant: false,
    showCreateReview: false,
    showReviews: false
  }
  async componentDidMount() {
    try {
      const rdata = await API.graphql(graphqlOperation(queries.listRestaurants))
      const { data: { listRestaurants: { items }}} = rdata
      this.setState({ restaurants: items })
    } catch(err) {
      console.log('error: ', err)
    }
  }
  viewReviews = (r) => {
    this.setState({ showReviews: true, selectedRestaurant: r })
  }
  createRestaurant = async(restaurant) => {
    this.setState({
      restaurants: [...this.state.restaurants, restaurant]
    })
    try {
      await API.graphql(graphqlOperation(
        mutations.createRestaurant,
        {input: restaurant}
      ))
    } catch(err) {
      console.log('error creating restaurant: ', err)
    }
  }
  createReview = async(id, input) => {
    const restaurants = this.state.restaurants
    const index = restaurants.findIndex(r => r.id === id)
    restaurants[index].reviews.items.push(input)
    this.setState({ restaurants })
    await API.graphql(graphqlOperation(mutations.createReview, {input}))
  }
  closeModal = () => {
    this.setState({
      showCreateRestaurant: false,
      showCreateReview: false,
      showReviews: false,
      selectedRestaurant: {}
    })
  }
  showCreateRestaurant = () => {
    this.setState({ showCreateRestaurant: true })
  }
  showCreateReview = r => {
    this.setState({ selectedRestaurant: r, showCreateReview: true })
  }
  render() {
    return (
      <div>
        <Header showCreateRestaurant={this.showCreateRestaurant} />
        <Restaurants
          restaurants={this.state.restaurants}
          showCreateReview={this.showCreateReview}
          viewReviews={this.viewReviews}
        />
        {
          this.state.showCreateRestaurant && (
            <CreateRestaurant
              createRestaurant={this.createRestaurant}
              closeModal={this.closeModal}   
            />
          )
        }
        {
          this.state.showCreateReview && (
            <CreateReview
              createReview={this.createReview}
              closeModal={this.closeModal}   
              restaurant={this.state.selectedRestaurant}
            />
          )
        }
        {
          this.state.showReviews && (
            <Reviews
              selectedRestaurant={this.state.selectedRestaurant}
              closeModal={this.closeModal}
              restaurant={this.state.selectedRestaurant}
            />
          )
        }
      </div>
    );
  }
}
export default App

We first create some initial state to hold the restaurants array that we will be fetching from our API. We also create Booleans to control our UI and a selectedRestaurant object.

In componentDidMount, we query for the restaurants and update the state to hold the restaurants retrieved from the API.

In createRestaurant and createReview, we send mutations to the API. Also notice that we provide an optimistic update by updating the state immediately so that the UI gets updated before the response comes back in order to make our UI snappy.

Next, we’ll create the Restaurants component ([src/Restaurants.js](https://github.com/dabit3/bigeats/blob/master/src/Restaurants.js "src/Restaurants.js")).

// src/Restaurants.js

import React, { Component } from 'react';
import { css } from 'glamor'

class Restaurants extends Component {
  render() {
    const { restaurants, viewReviews } = this.props
    return (
      <div {...css(styles.container)}>
        {
          restaurants.length === Number(0) && (
            <h1
              {...css(styles.h1)}
            >Create your first restaurant by clicking +</h1>
          )
        }
        {
          restaurants.map((r, i) => (
            <div key={i}>
              <img
                src={r.photo}
                {...css(styles.image)}
              />
              <p {...css(styles.title)}>{r.name}</p>
              <p {...css(styles.subtitle)}>{r.city}</p>
              <p
                onClick={() => viewReviews(r)}
                {...css(styles.viewReviews)}
              >View Reviews</p>
              <p
                onClick={() => this.props.showCreateReview(r)}
                {...css(styles.createReview)}
              >Create Review</p>
            </div>
          ))
        }
      </div>
    );
  }
}

export default Restaurants

This component is the main view of the app. We map over the list of restaurants and show the restaurant image, its name and location, and links that will open overlays to show reviews and create a new review.

Next, we’ll look at the Reviews component ([src/Reviews.js](https://github.com/dabit3/bigeats/blob/master/src/Reviews.js "src/Reviews.js")). In this component, we map over the list of reviews for the chosen restaurant.

// src/Reviews.js

import React from 'react'
import { css } from 'glamor'

class Reviews extends React.Component {
  render() {
    const { closeModal, restaurant } = this.props
    return (
      <div {...css(styles.overlay)}>
        <div {...css(styles.container)}>
          <h1>{restaurant.name}</h1>
          {
            restaurant.reviews.items.map((r, i) => (
              <div {...css(styles.review)} key={i}>
                <p {...css(styles.text)}>{r.text}</p>
                <p {...css(styles.rating)}>Stars: {r.rating}</p>
              </div>
            ))
          }
          <p onClick={closeModal}>Close</p>
        </div>
      </div>
    )
  }
}

export default Reviews

Next, we’ll take a look at the CreateRestaurant component ([src/CreateRestaurant.js](https://github.com/dabit3/bigeats/blob/master/src/CreateRestaurant.js "src/CreateRestaurant.js")). This component holds a form that keeps up with the form state. The createRestaurant class method will call this.props.createRestaurant, passing in the form state.

// src/CreateRestaurant.js

import React from 'react'
import { css } from 'glamor';

class CreateRestaurant extends React.Component {
  state = {
    name: '', city: '', photo: ''
  }
  createRestaurant = () => {
    if (
      this.state.city === '' || this.state.name === '' || this.state.photo === ''
    ) return
    this.props.createRestaurant(this.state)
    this.props.closeModal()
  }
  onChange = ({ target }) => {
    this.setState({ [target.name]: target.value })
  }
  render() {
    const { closeModal } = this.props
    return (
      <div {...css(styles.overlay)}>
        <div {...css(styles.form)}>
          <input
            placeholder='Restaurant name'
            {...css(styles.input)}
            name='name'
            onChange={this.onChange}
          />
          <input
            placeholder='City'
            {...css(styles.input)}
            name='city'
            onChange={this.onChange}
          />
          <input
            placeholder='Photo'
            {...css(styles.input)}
            name='photo'
            onChange={this.onChange}
          />
          <div
            onClick={this.createRestaurant}
            {...css(styles.button)}
          >
            <p
              {...css(styles.buttonText)}
            >Submit</p>
          </div>
          <div
            {...css([styles.button, { backgroundColor: '#555'}])}
            onClick={closeModal}
          >
            <p
              {...css(styles.buttonText)}
            >Cancel</p>
          </div>
        </div>
      </div>
    )
  }
}

export default CreateRestaurant

Next, we’ll take a look at the CreateReview component ([src/CreateReview.js](https://github.com/dabit3/bigeats/blob/master/src/CreateReview.js "src/CreateReview.js")). This component holds a form that keeps up with the form state. The createReview class method will call this.props.createReview, passing in the restaurant ID and the form state.

// src/CreateReview.js

import React from 'react'
import { css } from 'glamor';
const stars = [1, 2, 3, 4, 5]
class CreateReview extends React.Component {
  state = {
    review: '', selectedIndex: null
  }
  onChange = ({ target }) => {
    this.setState({ [target.name]: target.value })
  }
  createReview = async() => {
    const { restaurant } = this.props
    const input = {
      text: this.state.review,
      rating: this.state.selectedIndex + 1,
      reviewRestaurantId: restaurant.id
    }
    try {
      this.props.createReview(restaurant.id, input)
      this.props.closeModal()
    } catch(err) {
      console.log('error creating restaurant: ', err)
    }
  }
  render() {
    const { selectedIndex } = this.state
    const { closeModal } = this.props
    return (
      <div {...css(styles.overlay)}>
        <div {...css(styles.form)}>
          <div {...css(styles.stars)}>
            {
              stars.map((s, i) => (
                <p
                  key={i}
                  onClick={() => this.setState({ selectedIndex: i })}
                  {...css([styles.star, selectedIndex === i && { backgroundColor: 'gold' }])}
                >{s} star</p>
              ))
            }
          </div>
          <input
            placeholder='Review'
            {...css(styles.input)}
            name='review'
            onChange={this.onChange}
          />
          <div
            onClick={this.createReview}
            {...css(styles.button)}
          >
            <p
              {...css(styles.buttonText)}
            >Submit</p>
          </div>
          <div
            {...css([styles.button, { backgroundColor: '#555'}])}
            onClick={closeModal}
          >
            <p
              {...css(styles.buttonText)}
            >Cancel</p>
          </div>
        </div>
      </div>
    )
  }
}

export default CreateReview

Running the app

Now that we have built our back-end, configured the app and created our components, we’re ready to test it out:

npm start

Now, navigate to [http://localhost:3000](http://localhost:3000 "http://localhost:3000"). Congratulations, you’ve just built a full-stack serverless GraphQL application!

Conclusion

The next logical step for many applications is to apply additional security features, like authentication, authorization and fine-grained access control. All of these things are baked into the service. To learn more about AWS AppSync security, check out the documentation.

If you’d like to add hosting and a Continuous Integration/Continuous Deployment pipeline for your app, check out the Amplify Console.

I also maintain a couple of repositories with additional resources around Amplify and AppSync: Awesome AWS Amplify and Awesome AWS AppSync.

#graphql #aws

What is GEEK

Buddha Community

An introduction GraphQL with AWS AppSync
Lindsey  Koepp

Lindsey Koepp

1594688114

AWS Amplify and GraphQL— an Introduction

Amplify is a product from AWS that has two aspects to it:

  • Amplify framework which as an open-source framework which provides a CLIlibraries to integrate frontend code with the backend and UI components to build fullstack iOS, Android, Web, and React Native apps. You can configure and integrate the underlying cloud services like AWS AppSync (Managed GraphQL, offline data sync), Amazon Cognito (Authentication, Authorization, User Management, MFA), Amazon Pinpoint (Analytics, Customer Engagement), AWS Lambda (GraphQL Resolver, Business logic), Amazon S3 (Storage), or Amazon Lex (Conversation Bots) directly from your command line minimizing the time required to set-up and manage your back-end services.
  • The Amplify Console provides a Git-based workflow for hostingfullstack serverless web apps with continuous deployment.

Image for post

It also supports static-site generators like **Gatsby, Eleventy, Hugo, VuePress, **and Jekyll. You can deploy serverless backends with GraphQL/REST APIsauthenticationanalytics, and storage created by the Amplify CLI on the same commit as your frontend code.

Important: You can use Amplify console to deploy and host Single Page App (SPA) frontends and static websites, without using the Amplify Framework.

GraphQL

Amplify supports GraphQL, which is yet another API technology just like REST, SOAP, gRPC, Thrift, OpenAPI (Swagger) etc. First of all, GraphQL is not a Graph database query language. GraphQL is a query language for your APIs which offers a strong type system, great tools for **domain modelling **and many other features.

Components

  • **Schema — **Each GraphQL API is defined by a single GraphQL schema. A GraphQL server’s type system is referred to as that server’s schema. All data operations are validated against this schema. GraphQL comes with a set of default scalar types out of the box (Int, Float, String, Boolean, ID), allows you to create own scalar / object types and supports interfacesunion and list types.
  • **Data Source — **This is the source of the data for the GraphQL API. The data source could be of any type, as long as one is authorized to read from it.
  • Resolvers — Resolvers are the components that connect with the data source and are able to map a schema with it.

Note: GraphQL isn’t tied to any specific database or storage engine and is instead backed by your existing code and data.

In GraphQL, you define certain types as part of domain modelling which are part of your schema. In the following image, the “!” at the end of the type means that the field is required or Not-Null.

#graphql #full-stack #aws-amplify #serverless #aws #graphql

Fredy  Larson

Fredy Larson

1599105420

AWS AppSync: Conditional Resolvers Using the Info Context

AWS AppSync

AppSync is a managed GraphQL service offered by Amazon Web Services and can be used to build scalable enterprise APIs. A typical AppSync solution consists of small resolvers that can be combined to access various data sources such as databases, HTTP APIs or AWS Lambda.


Introduction

In this example, I will be talking about using AWS AppSync with AWS Lambda data sources and one of the challenges I have come across while developing enterprise scale solutions with these technologies.

Each Lambda resolver you have in a particular request triggers an invocation. The problem comes with having nested resolvers where you only request data from the nested Lambda rather than the parent Lambda. As a result you will cause several invocations, incur cost and resource for the first Lambda without needing to.

If you’re running enterprise serverless it is important to consider the architecture to reduce the amount of compute where possible and lower the risk of hitting limits imposed by AWS.

Thankfully, AWS released an AppSync update in Feb 2020 giving us access to the context info object so we can mitigate this issue. Read more here.

Let’s dive in! 💥

Say you have a GraphQL endpoint and schema to retrieve a typical blog post:

type Post{
  id: ID!
  title: String!
  content: String!
  image: ImageData!
}
type ImageData{
  id: ID!
  postId: ID!
  path: String!
  tags: String
}
type Query{
  getPost(id: ID!): Post!
}

Using GraphQL, your query could look like:

query GetPost{
  getPost(id: $id){
    title
    content
    image{
      path
      tags
    }
  }
}

#aws-appsync #graphql #aws-lambda #serverless #aws

Chaz  Homenick

Chaz Homenick

1596762420

Effective Direct Lambdas for AWS AppSync (Spoiler: They Are Really Effective)

Today, I’m going to walk you through using AppSync’s Direct Lambda feature. I built the thing during my internship this Summer after all, so I should be able to express how simple, yet effective, this feature is in allowing you to configure Lambdas for your API on AppSync.

_Go ahead and jump to the section labelled __Let there be an API! _if you’d like to skip the bits about what the old workflow for a Lambda resolver was like.

I’d first like to make a point about why Direct Lambdas were necessary. Here’s a picture to help demonstrate that point.

Image for post

VTL? Cancelled, sorta. Call the mob.

In order to set up a Lambda resolver for a field on AppSync, you’d first have to check out the resolver mapping template reference, then you’d have to set up your mapping templates in a language called VTL. These templates translate data back and forth between your Lambda. Finally, you’d be able to set up your Lambda to expect the data as translated by the mapping templates.

Notice that I mentioned that you had to write code in two separate places: the Lambda and the mapping templates, which might be in the Appsync console editors, uploaded through the SDK, or in a CloudFormation template. This introduces unnecessary coupling between your Lambda code and your mapping templates, which is probably not optimal for your code-base, nor your mental health.

This is where the problem lies: if it’s at all complicated, then it’s too complicated. The goal is to think less… Er, less about things that don’t matter, that is.

If only there was an easier way to configure a Lambda resolver on AppSync. If only there was a way to write less code and get more done.

There is now a way, Direct Lambdas.

Image for post

This is probably how things work under the hood.

Let there be an API!

I’d like to avoid making this tutorial dry and boring so I’ve decided that our API will be all about awesome, original, definitely-not-cringe dad jokes! Plus, we can utilize a friendly API called icanhazdadjokes that offers an unprecedented collection of definitely-not-cringe-worthy dad jokes for free. That’s a low price!

Let’s start off with a specification of what our API should do. I’d like to create an API that will allows a client to either get a random Joke or get a Joke specified by an ID.

What makes up a Joke?

  • joke: The content of the joke
  • id: The id of the joke
  • imageUrl: A permalink to the joke
  • cringe: A boolean that shows if the joke is cringe or not

Here’s how the entire thing will work:

Image for post

#aws #graphql #serverless #aws-lambda #aws-appsync

Landen  Brown

Landen Brown

1625819340

AWS Amplify - AWS AppSync GraphQL Codegen Demo

The AWS Amplify CLI toolchain now automatically generates your GraphQL queries, mutations, & subscriptions as well as a typed API file containing your Schema. In this video, we walk through how to use it.

https://aws-amplify.github.io/

#graphql #aws appsync #aws amplify #codegen

Landen  Brown

Landen Brown

1625815680

Creating AWS AppSync GraphQL APIs with AWS Amplify

In this video, we walk through how to create a new AWS AppSync GraphQL API & connect to it from a client-side application.

#aws amplify #aws appsync #graphql