I have used both Ionic and AWS for years now. Both technologies are (mostly) free and awesome.
Ionic is the badass framework to build cross-platform mobile applications and AWS gives us the tools to host, cache, manipulate files with authentication and many more services in the cloud.
So what’s the result if both companies allied together to create a project: the Ionic AWS Starter!
Until now, I have only used the S3 service so this stack gave me a new look at AWS potential.
The AWS Mobile Hub
Instead of creating the backend in Java, Ruby or Node.js, AWS offers some services that can be easily configured by clicking some buttons.
Those services are centered in one place: the Mobile Hub.
As you can see from this picture, there are nine types of services. Only five are used in our stack:
- NoSQL Database
- User Data Storage
- User Engagement
- Hosting and Streaming
As I said before, most of those services can be activated with just one click:
We can start from zero, add the services one by one or import them, which brings us back to the starter project.
The Ionic project already have a mobile-hub-project.zip file that contains a configuration for the Mobile Hub, so most of the work is already done for us.
If we unzip the file, we can have a look at the yaml configuration:
This configuration is very concise. We only need 60 lines to create five features. Not bad right?
Let’s focus on the sign-in feature, the attributes will specify the type of authentication (ex: email), how strong the password should be or if signing in is optional or required.
Taking a step back, the authentication is designed on the backend (the Mobile Hub) to be optional.
When launching our app:
This doesn’t look optional 🤔.
Aside from that, what does the mobile app do?
In a nutshell, it allows a user to create an account, connect, add some tasks, change its profile picture and disconnect.
Those actions cover a good spectrum of use cases showcasing the use of:
- AWS S3 for stocking the profile picture
- Cognito for authentication
- DynamoDB for stocking the tasks details
- Ionic Native for the use of the camera
The architecture is as follow:
Nothing new about the pages, each feature is separated in its own folders.
Provider wise, every AWS Services are available in the providers folder: Cognito, DynamoDb and User.
The providers.ts file exports those services:
Special mention to the assets folder which contains the AWS libraries:
Why not using the package.json to acquire those files?
Two possible reasons:
- They use a custom AWS version, different from the public one
- They want AWS to be loaded before other Angular and Ionic files, in the index.html file:
Aside from the AWS core libraries, the aws.config.js file is very important, this file sets multiple global constants that will be used for configuration like the region, the bucket, etc.
Those constants are then acquired in the app.config.ts file:
We will encounter this again and again and again in this project.
Typically, this could have been placed once and for all in a declaration.d.ts file in order to be available everywhere.
The app.module.ts file is just business as usual, except:
All our previous configurations are merged with Ionic’s Config.
Moving on to the Providers.
Starting with the simplest one: DynamoDB.
Located in the aws.dynamodb.ts file:
This Service creates the document client and an accessor.
The document client is our god object that will allow us to manipulate the database.
The documentation is there, with every traditional db commands: put, delete, get, query…
Followed by the Cognito service.
Located in the aws.cognito.ts file:
Which starts with some imports and declarations.
In the constructor, we setup AWSCognito with the configuration we talked about earlier:
- The region where the endpoints are located (ex: us-east-1)
- The IdentityPoolId: A unique identifier pointing to the Cognito Service
- The CustomUserAgent: In order to avoid user agent filters (ex: bot defense), the user agent is set to “MobileHub v0.1”
Followed by the getUserPool method:
Setting up the access to AWSCognito’s user pool.
Important workaround here, the this object is stocked in another variable named self in order to keep it available in the CognitoUserPool method.
Let’s avoid the confusion!
The UserPoolId represents where the clients are stocked whereas the ClientId authenticates applications that connect to this user pool:
Those ids are available in the mobile-hub-project.yml configuration file and on the AWS Mobile Hub webpage.
Once we have access to the user pool, we can:
- Access a user from the pool:
- Get the current user:
- Create authentication data:
- Create a user attribute:
We are now done with the Cognito Service.
Moving on to the last one: the User Service.
This Service will use the Cognito Service’s methods.
Two interesting properties here:
- user: Will stock the Cognito user once logged in
- loggedId: A simple flag (not yet used)
The registration part:
When a user registers, its attributes (name, address, etc.) must go through some transformations in the makeAttribute method.
A Promise is returned so the flow can progress.
Then the user is signed up to the user pool. Finally, if everything is good, the user is returned.
If the user forgot its registration code:
Using the username, the makeUser method is used to grab the matching user then the built-in resendConfirmationCode method is used (we didn’t code this one, many methods come from the Cognito user object #profit).
Once the user has the code:
Same as before, the makeUser method gives us the Cognito user and we check if the code is good by using the confirmRegistration method.
More code in the login method:
The login method will get the user matching the username.
It will compare it to the information from authDetails using the authenticateUser method.
If everything is good, we receive a result that contains a token.
The loginKey string can be scary, but in the end it’s just a path to the user pool located in our region.
This path is associated to the token we received. Using this path and our Cognito’s IdentityPoolId, we can now set the credentials for AWS.
Those credentials will automatically be added to our future requests.
The final touch is the isAuthenticated method:
First we grab the current user, if he does exist, we look if we can get a session.
Once again the loginKey variable is created. This time the token comes from the session itself.
Finally, the user is stocked in the user property of the User Class.
Remember, this one:
Let’s not forget the logout method!
Cleaning up our local user and signing out the user from Cognito’s user pool.
And Voila we are done with our Providers!
In this tutorial we have seen the most complex parts of the application: AWS configuration and Providers creation.
The rest of the application will use those parts in order to communicate with the AWS Services to handle the users, the tasks and the profile pictures.
The AWS Mobile Hub is super cool to use!
It’s the first time that I can configure so many complex services by only using a few clicks.
In the next tutorial we will have a look at how the Providers are integrated into the application’s business logic.
Until next time.