Building Full Stack Serverless Application With Amplify, Flutter, GraphQL, AWS CDK, and Typescript

Building Full Stack Serverless Application With Amplify, Flutter, GraphQL, AWS CDK, and Typescript

notes.jpg In this tutorial series, you will learn how to build a Full Stack serverless Mobile application using GraphQL, Typescript, AWS CDK(Cloud Development Kit), and Flutter.

Solutions Architecture

notes_draw.png We'll start by building a GraphQL API using Typescript and AWS CDK(Cloud Development Kit) as Infrastructure as Code. The API would allow for both public and private access.
Then, we will build a mobile frontend using Amazon Amplify and Flutter, which would consume the GraphQL API.

In a previous article Build a GraphQL API on AWS with CDK, Python, AppSync, and DynamoDB we looked at creating a GraphQL API with python and AWS CDK. We used Apache VTL templates as our resolvers.
In this series, we will be using lambda functions as resolvers. I personally prefer using direct lambda functions as resolvers and I'll tell you why in a moment.

If you are new to GraphQL and AppSync in general, you might start asking yourself questions like?

  • What is GraphQL?
  • What are resolvers?
  • What are VTL templates?
  • Why did you prefer using direct lambda functions to VTL templates as resolvers? Confused


Lots of Why's......

It's quite a long series, So let's get started.

Basic Overview of Some Concepts

What is GraphQL ?

GraphQL is aggressively becoming the new kid on the block when it comes to querying data from a data source. Partly due to its ability to let clients query only the data they need at that moment and in the format that they need it.

GraphQL is a query language that gives a client(app) the flexibility to request specific data in a declarative manner and in the exact format they need it, from a server.

The QL in Graph stands for Query Language.

GraphQL has three top-level operations:

  • Query - read-only fetch

  • Mutation - write, followed by a fetch

  • Subscription - long-lived connection for receiving data.

These operations are exposed via a schema that defines the capabilities of an API.
A schema is composed of 2 types

  • root type (Query, Mutation, Subscriptions)
  • user-defined type. (Note) The first step in creating a GraphQL API is creating a schema.
    Here’s an example schema that has both root types and a user-defined type.
type Note {
id:ID!
title:String!
description:String!

}
type Query {

getNoteById(id:ID!):Note

listAllNotes:[Note]
.......
......
}
type Mutation {
createNote(id:ID!,title:String!,description:String!):Note
.....
....

}
type Subscription {
onCreateNote:Note @aws-subscribe(mutations:["createNote"])

.......
.........
}

Note is a user-defined type with 3 fields.(id,title,description).
The ID, String at the end of each field is known as a scalar type. There are other scalar types such as Int, Float, Bool, and a lot more.
The ! At the end of a scalar type marks it as non-nullable. It must always have a value.
Query is a root type and it defines the endpoints that our application would use to query(retrieve) data from datasources. From the code above, we have getNoteById and listAllNotes

getNoteById(id:ID!):Note

The above endpoint, retrieves a single Note object by passing the Note item's id. :Note specifies the object which should be returned.

listAllNotes:[Note]

Retrieve a list of all Notes from the data source. :[Note] signifies a return type of Note in a list format.
Mutations contain endpoints responsible for write operations,that are followed by a fetch.
For example,

createNote(id:ID!,title:String!,description:String!):Note

The Above endpoint creates a new Note by passing in the id, title, and description, and then returns a Note object on success.
The Mutation type can also contain updateNote,deleteNote, etc as we'll see later.

Subscriptions in AWS AppSync are invoked as a response to a mutation and are used to create long-lived connections for receiving data.
In the above subscription, we create a connection to receive new Notes whenever they are created.

onCreateNote:Note @aws-subscribe(mutations:["createNote"])

@aws-subscribe is a directive that is used to decorate the subscription endpoint, giving it subscription capabilities.

What are resolvers ?

We just defined the types above. User types and root types. Resolvers simply connect the fields of those types to a data source. There are multiple data sources you can connect to. A NoSQL database like DynamoDB, A relational database like Amazon Aurora, a lambda function an elastic search engine, etc.
I urge you to learn more about GraphQL - graphql.org - GraphQl Overview

What are VTL Templates

Also known as Apache Velocity Template Language, is a logical template language that gives you the power to manipulate both the request and the response in the standard request/response flow of a web application, using techniques such as - Default values for new items - Input validation and formatting - Transforming and shaping data - Iterating over lists, maps, and arrays to pluck out or alter values - Filter/change responses based on user identity - Complex authorization checks AWS AppSync uses VTL to translate GraphQL requests from clients into a request to your data source. Then it reverses the process to translate the data source response back into a GraphQL response.

Why did you prefer using direct lambda functions to VTL templates as resolvers?

  • Easier to write and maintain
  • More powerful for marshaling and validating requests and responses
  • Common functionality can be more DRY than possible with VTLs (macros are not supported)
  • More flexible debugging and logging
  • Easier to test
  • Better tooling and linting are available

That was a brief overview of some of the concepts we would be using in this series.

Let's get started developing the API in the next article coming up soon

Happy Coding ✌🏿

PEACE