Building a Scalable Event Keeper App with Ionic and AWS
Getting Started
In this guide, we’ll walk you through the process of building a high-performance event keeper app using the Ionic framework and Amazon Web Services (AWS). Our app will allow users to upload images and store them in an AWS S3 bucket, making it easily accessible and scalable.
Prerequisites
Before we dive in, make sure you have:
- A basic understanding of HTML, CSS, and JavaScript (ES6+)
- A code editor, such as VS Code, installed
- POSTMAN installed
- MongoDB set up
- Basic knowledge of Angular and Express.js
Building the Backend
To build the backend, follow these steps:
Initialize a New Node Project
mkdir event-app && cd event-app
Inside the event-app directory, create a server directory, where we’ll set up our backend application.
Install Required Dependencies
Our application will need the following npm packages for development:
- Express.js
- Mongoose
- Body-parser
- CORS
- Morgan
- AWS SDK
- Multer
- Multer-S3
- Nodemon
<li.dotenv< li=””>
</li.dotenv<>
npm install express mongoose body-parser cors morgan aws-sdk multer dotenv multer-s3 nodemon
Create an Express Server and Configure Dependencies
Create a src directory and place an index.js file inside it. This is the base file for our application, where we’ll define our first route and configure some packages.
Create and Configure MongoDB Database
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/event-app', { useNewUrlParser: true, useUnifiedTopology: true });
Create the Event Keeper Model
const mongoose = require('mongoose');
const eventSchema = new mongoose.Schema({
name: String,
description: String,
image: String
});
const Event = mongoose.model('Event', eventSchema);
module.exports = Event;
Set up AWS and Multer
First, register for an AWS account and create a new bucket for your application. Then, create a.env file and add the following code to store your AWS security credentials:
AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY
const AWS = require('aws-sdk');
const multer = require('multer');
const multerS3 = require('multer-s3');
AWS.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: 'your-region'
});
const s3 = new AWS.S3();
const upload = multer({
storage: multerS3({
s3: s3,
bucket: 'your-bucket-name',
acl: 'public-read',
key: function(req, file, cb) {
cb(null, Date.now().toString() + '-' + file.originalname);
}
})
});
module.exports = upload;
Create the Necessary Routes and Controllers
const express = require('express');
const router = express.Router();
const Event = require('../models/Event');
const upload = require('../config/aws');
router.get('/events', async (req, res) => {
const events = await Event.find().exec();
res.json(events);
});
router.post('/events', upload.single('image'), async (req, res) => {
const event = new Event(req.body);
event.image = req.file.location;
await event.save();
res.json(event);
});
module.exports = router;
Test the Application on POSTMAN
Use POSTMAN to test our application by posting an event and getting all events.
Setting Up the Mobile App
Install Ionic and other Ionic tools globally:
npm install -g @ionic/cli
Create a new directory called events on your desktop and init a new Ionic application and Angular inside that directory:
ionic start events tabs --type=angular --capacitor
Setting Up the User Interface
Customize the tabs by modifying the code in src/app/tabs/tabs.page.html. Use cards to represent our events, and modify the code in src/app/tab1/tab1.page.html.
Creating the Event Service
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class EventService {
private apiUrl = 'http://localhost:3000/api';
constructor(private http: HttpClient) { }
getEvents() {
return this.http.get(`${this.apiUrl}/events`);
}
addEvent(event: any) {
return this.http.post(`${this.apiUrl}/events`, event);
}
}
Implementing the APIs
Bring our services into our tab1 and tab2 components. Edit the code in src/app/tab1/tab1.page.ts to display all the events in our database.
import { Component, OnInit } from '@angular/core';
import { EventService } from '../event.service';
@Component({
selector: 'app-tab1',
template: `
<ion-header>
<ion-toolbar>
<ion-title>Events</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-card *ngFor="let event of events">
<ion-card-header>
<ion-card-title>{{ event.name }}</ion-card-title>
</ion-card-header>
<ion-card-content>
{{ event.description }}
</ion-card-content>
</ion-card>
</ion-content>
`
})
export class Tab1Page implements OnInit {
events = [];
constructor(private eventService: EventService) { }
ngOnInit(): void {
this.eventService.getEvents().subscribe(events => {
this.events = events;
});
}
}
Implement the add event method in src/app/tab2/tab2.page.ts using Angular’s reactive forms.
import { Component } from '@angular/core';
import { EventService } from '../event.service';
import { FormGroup, FormControl, Validators } from '@angular/forms';
@Component({
selector: 'app-tab2',
template: `
<ion-header>
<ion-toolbar>
<ion-title>Add Event</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<form [formGroup]="addEventForm">
<ion-item>
<ion-label>Name</ion-label>
<ion-input formControlName="name"></ion-input>
</ion-item>
<ion-item>
<ion-label>Description</ion-label>
<ion-textarea formControlName="description"></ion-textarea>
</ion-item>
<ion-item>
<ion-label>Image</ion-label>
<ion-input type="file" formControlName="image"></ion-input>
</ion-item>
<ion-button type="submit">Add Event</ion-button>
</form>
</ion-content>
`
})
export class Tab2Page {
addEventForm = new FormGroup({
name: new FormControl('', Validators.required),
description: new FormControl('', Validators.required),
image: new FormControl('', Validators.required)
});
constructor(private eventService: EventService) { }
addEvent() {
this.eventService.addEvent(this.addEventForm.value).subscribe(event => {
console.log(event);
});
}
}
Adding Spinners and Toast
Add preloaders and a toast to show users whether the add event method was successful or not. Import LoadingController and ToastController and register them in the constructors.
import { LoadingController, ToastController } from '@ionic/angular';
@Component({
selector: 'app-tab2',
template: `
<ion-header>
<ion-toolbar>
<ion-title>Add Event</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<form [formGroup]="addEventForm">
...
</form>
</ion-content>
`
})
export class Tab2Page {
...
constructor(private eventService: EventService, private loadingCtrl: LoadingController, private toastCtrl: ToastController) { }
addEvent() {
this.loadingCtrl.create({
message: 'Adding event...'
}).then(loading => {
loading.present();
this.eventService.addEvent(this.addEventForm.value).subscribe(event => {
loading.dismiss();
this.toastCtrl.create({
message: 'Event added successfully!',
duration: 2000
}).then(toast => {
toast.present();
});
}, error => {
loading.dismiss();
this.toastCtrl.create({
message: 'Error adding event!',
duration: 2000
}).then(toast => {
toast.present();
});
});
});
}
}
Congratulations! You’ve just built a simple event app using Ionic and AWS.
What’s Next?
You can improve your app by adding better features, such as user sign-in and sign-up. Understanding how both backend and mobile apps communicate will help you build larger, more complex, and feature-rich applications.