Overview
This concept is all about how Mule API-Led connectivity can be extensively utilized to create an application network of MuleSoft APIs. TravelZoom can be used by the people in the UK, who use train services as the mode of transportation for going to their workspace, shopping or even on a vacation. The application provides users with the facilities of registering with the system, and once successfully registered the user can search for the trains routed through a specified source and destination location for a given time period. The search for trains can be done using postcodes as well. That's not all, along with this considering the Covid-19 situation, and travel well being of the user this application also includes the features such as- providing Covid-19 updates for the destination location, the weather conditions, links to the local food sources including restaurants and grocery stores, and as a cherry on top any delays in the subscribed train journey will be notified prior to a user-configured time on the day of travel. This additional information gives a heads up to the user to plan his journeys well in advance considering his/her time and safety.
Technical Design Diagrams
Use Case Diagram
Architecture Diagram
Layered Viewpoint- MyTrains Service
Layered Viewpoint- Customer Notification Service
Sequence diagram
Process View- MyTrains Service
Process View- Customer Notification Service
ER Diagram for TravelZoom Database
User Experience (UI)
The front-end application is created using Angular 11, Bootstrap, ng2-charts for displaying covid and css3.
Users can search on the basis of Source, Destination and Travel date. In the Source, location can be either a Location name or a postal code. Same is applies for the Destination. For the travel date, we have to specify the date of travel.
Then two tabs in UI Travel and NearBy shows the weather, Covid cases in different regions and train services from the source to destination are displayed.
Below are the screenshots of UI exhibiting the explained features, which has been enclosed using RED rectangular boxes.
Note: The UI has been integrated with the following endpoints from experience API:
- /myTravel/locations/stations
- /myTravel/locations/stations/trains
- /myTravel/locations/forecast
- /myTravel/locations/attractionspots
- /myTravel/locations/covid
- /myTravel/locations/covid/areaname
Rest of the endpoints are fully functional and can be tested using any API testing tool. The UI integration with the remaining APIs is moved to future extension scope.
MuleSoft Implementation
The MuleSoft implementation for the TravelZoom is designed following the API-Led connectivity approach, having the APIs created in the Experience Layer, Process Layer and System Layer based on their functionality and integration with external systems.
Experience Layer
The NodeJs front-end application integrates with the myTravel Experience API, which exposes REST endpoints for managing User(s) in the system, the Subscriptions for train services to multiple locations during a specific time period. Endpoints for retrieving location data, covid case count, and weather forecast. Below are the resources exposed by the Exp API to the external world:
-
/register:
- POST- endpoint for creating a new user initially creating a user account in Okta for single sign-on, followed by saving the user details into the application database.
-
/login:
- POST- endpoint for a registered user to login into the application by providing Username and Password.
-
/forgotPassword:
- POST- accepts customer email as payload for initiating a password reset, for which the link would be sent to the provided email address.
-
/myTravel/users/{userId}:
- GET- Get user details by user Id.
-
/myTravel/users/{userId}/subscriptions:
- GET- Get all Subscriptions for a specific user.
-
/myTravel/users/{userId}/subscriptions:
- POST- Create subscription for trains routed between given two locations in given time window.
-
/myTravel/users/{userId}/subscriptions/{subscriptionId}:
- GET- Retrieve subscription details for a particular train service for the selected user.
-
/myTravel/users/{userId}/subscriptions/{subscriptionId}:
- DELETE- Unscubscribe to a service that a user has subscribed to.
-
/myTravel/locations/stations:
- GET- Returns a list of all stations and codes.
-
/myTravel/locations/stations/trains:
- GET- Fetches train services between source and destination location on a particular date.
-
/myTravel/locations/forecast:
- GET- Provides weather forecast for the selected date and location.
-
/myTravel/locations/attractionspots:
- GET- Retrieves restaurants, tourist and cinema spots near a location.
-
/myTravel/locations/covid:
- GET- Get all COVID-19 case details for entire UK.
-
/myTravel/locations/covid/areaname:
- GET- Get COVID details for UK by Area name
RAML Specification For Experience API
Below is the RAML specification for the experience API that provides a detailed representation of the methods, request and response structures with examples for each REST endpoint.
#%RAML 1.0
title: myTravel Experience API
version: v1
mediaType:
- application/json
protocols:
- HTTP
traits:
responseMessage: !include /resources/traits/error-trait.raml
uses:
myTrains: /exchange_modules/cd5bf5d6-a7c5-40f7-a8db-9f1046bbc2fd/mytrains-datatype-library/1.0.10/mytrains-datatype-library.raml
locations: /exchange_modules/cd5bf5d6-a7c5-40f7-a8db-9f1046bbc2fd/locations-data-type-library/1.0.4/locations-data-type-library.raml
types:
user: myTrains.user
subscription: myTrains.subscription
token: myTrains.token
station: myTrains.station
forecast: locations.forecast
attractionSpots: locations.attractionspots
covidbyregion: locations.covidbyregion
covidbyarea: locations.covidbyarea
stationLocation: locations.stationLocation
trainService: myTrains.trainService
alertData: myTrains.alert
/myTravel:
displayName: myTravel
/register:
displayName: Register User
description: Used to register and update user
post:
is: [ { responseMessage: { messageReference : Error registering user. } } ]
displayName: Register
description: Register new user.
body:
application/json:
displayName: Registered User Details
description: User details to store in database.
type: user
example: !include /resources/examples/register-input-example.raml
responses:
201:
description: Success
body:
application/json:
example:
message: User registered successfully.
/login:
displayName: Login
post:
description: This method is used to create token for login details
body:
application/json:
type: object
example:
strict: true
value:
email: train.alerts@alert.com
password : "testpass"
responses:
"500":
body:
type:
type: any
"201":
body:
type: token
examples:
output: !include /resources/examples/token-example.raml
"400":
body:
type:
type: any
/forgotPassword:
displayName: Forgot Password
description: Forgot Password operation
post:
is: [ { responseMessage: { messageReference : Error resetting password. Try again later. } } ]
displayName: Forgot Password
description: Forgot Password
body:
application/json:
displayName: Username
description: Username of the customer.
type: string
examples:
output: "jane.doe@example.com"
responses:
201:
description: Success
body:
application/json:
example: "https://dev-462737.okta.com/signin/reset-password/XE6wE17zmphl3KqAPFxO"
/users:
displayName: Users
/{userId}:
displayName: User ID
description: Used for logged in user operations
get:
is: [ { responseMessage: { messageReference : User ID retrieval unsuccessful. } } ]
displayName: Get User
description: Retrieves user details
responses:
200:
description: Success
body:
application/json:
type: user
examples:
output: !include /resources/examples/userDetailsExample.raml
/subscriptions:
displayName: Subscriptions
description: Subscription to train services between two locations in particular time window.
get:
is: [ { responseMessage: { messageReference : Error retrieving all subscriptions. } } ]
displayName: Get All Subscriptions
description: Get details of all subscriptions for given user
responses:
200:
description: Success
body:
application/json:
type: subscription[]
examples:
output: !include /resources/examples/all-subscriptions-example.raml
post:
is: [ { responseMessage: { messageReference : Error creating subscription. } } ]
displayName: Create Subscription
description: Create subscription for trains between given two locations in given time window
body:
application/json:
displayName: Subscription details
description: Details of location, time window and advance notification time for subscription.
type: subscription
examples:
input: !include /resources/examples/create-subscription-input-example.raml
responses:
201:
description: Success
body:
application/json:
example:
message: Successfully created subscription.
/{subscriptionId}:
displayName: Subscription ID
get:
is: [ { responseMessage: { messageReference : Error retrieving subscription details. } } ]
displayName: Get Subscription Details
description: Get details of subscription with given ID
responses:
200:
description: Success
body:
application/json:
type: subscription
examples:
output: !include /resources/examples/subscription-details-example.raml
delete:
is: [ { responseMessage: { messageReference : Error deleting subscription. } } ]
displayName: Unsubscribe
description: Unsubscribe to a subscription
responses:
200:
description: Success
body:
application/json:
example:
message: Successfully deleted subscription.
202:
description: Accepted
body:
application/json:
example:
message: Subscription queued to be deleted.
204:
description: Success. No content to display.
/locations:
displayName: Locations
/stations:
displayName: Stations
get:
displayName: Get all Stations
description: Returns list of all stations and codes
responses:
200:
description: Success
body:
type: station[]
examples:
output: !include /resources/examples/station-list-example.raml
/nearby:
displayName: Near By Station
get:
is: [{ responseMessage: { messageReference : Error retrieving stations nearby. } }]
displayName: Get nearby stations
description: Fetches the nearby stations with station codes and post code
queryParameters:
address:
displayName: address
description: Post code or Location Name
example: "DE21"
type: string
responses:
200:
description: Success
body:
type: stationLocation[]
examples:
output: !include /resources/examples/nearby-stations-example.raml
/trains:
displayName: Trains
get:
is: [{ responseMessage: { messageReference : Error retrieving trains services. } }]
displayName: Get trains
description: Fetches train services between source and destination location on a particular date
queryParameters:
origin:
displayName: Origin Station
description: Origin Station
example: "London St Pancras International"
type: string
originType:
displayName: Origin Type
description: Origin Type
example: "P"
type: string
destination:
displayName: Destination Station
description: Destination Station
example: "Looe"
type: string
destType:
displayName: Destination Type
description: Destination Type
example: "L"
type: string
travelDate:
displayName: Travel Date
description: Travel Date
example: 2020-11-27
type: date-only
responses:
200:
description: Success
body:
type: trainService[]
examples:
output: !include /resources/examples/json/train-service-response.json
/forecast:
displayName: Forecast
get:
is: [{ responseMessage: { messageReference : Error fetching weather forecast. } }]
displayName: Get Forecast
description: Gives forecast for following five days
queryParameters:
city:
displayName: City Name
description: City Name
example: "New York"
type: string
date:
displayName: Date
description: "5 days forecast is provided including current day (dateformat- 'yyyy-MM-dd')"
example: "2020-11-23"
type: string
countryCode:
displayName: Country Code
description: Country code as query parameters like us, uk…. e.t.c.
example: "us"
type: string
required: false
units:
displayName: units
description: Units like metric, imperial and standard as default
type: string
required: false
responses:
200:
description: Success
body:
type: forecast
examples:
output: !include /resources/examples/json/forecast-response-example.json
/attractionspots:
displayName: Attraction Spots
get:
is: [ { responseMessage: { messageReference : Error fetching attraction spots. } } ]
displayName: Get attraction spots
description: Retrieves restaurants, tourist and cinema spots near a location
queryParameters:
city:
description: name of the place/city
type: string
required: true
example:
new york
responses:
200:
body:
application/json:
type: attractionSpots
examples:
output: !include /resources/examples/json/attraction-spots-response-example.json
/covid:
displayName: COVID Update
get:
is: [ { responseMessage: { messageReference : Error fetching COVID updates. } } ]
displayName: Get Update
description: Get all COVID details for UK
responses:
200:
body:
application/json:
example:
output: !include /resources/examples/covid-by-region-example.raml
/areaname:
displayName: COVID Update By Area
get:
is: [ { responseMessage: { messageReference : Error fetching COVID updates. } } ]
displayName: Get Update by Area
description: Get COVID details for UK by Area
responses:
200:
body:
type: object[]
examples:
output: !include /resources/examples/json/covid-by-area-example.json
Process Layer
The njc-mytravel-experience-api invokes the following 2 process APIs:
- mytrains-process-api: Supports CRUD operations on users or service subscriptions.
- notification-process-api: Checks and notify the users about the delays in train service, retrieving train and station details, location details, weather forecast and Covid case count based on location and date.
For more information on the endpoints for the process APIs please refer the RAML specification in Git: https://github.com/smeghakumar/RAML.git
System Layer
The System APIs share a bounded context with the external systems the communicate with and hence we one System API per external system entity.
The mytrains-process-api invokes the following system APIs:
-
mytrains-system-api: This API communicates with the MySQL database to perform:
- An INSERT, UPDATE and DELETE operations on the user and user subscriptions,
- INSERT alert details,
- INSERT and SELECT operation on railway station details
-
okta-system-api: Okta API is used for enabling single sign-on for the travelzoom users. The core operations of this API include:
- Creates a user in Okta
- Authenticate and Authorize Users
- Forgot password option for a password reset
- Deactivate user
-
nre-system-api: The system API checks for delays in train services for the immediate 60 minute time frame and notifies the users by sending Emails. This is done by comparing the actual arrival train time and estimated arrival time from the train details retrieved from the external NationalRail API. The two operations can be summarized as:
- Fetch all station codes and station names
- Get services for provided origin, destination and date
- train-details-system-api: Retrieves train details such as- arrival and departure time, source and destination locations, train number, and total duration for the journey.
The notification-process-api invokes the following system APIs:
- delay-notification-system-api: It connects with the MySQL database tables for retrieving the Subscriptions details whose train time falls between the 60-minute window from that moment.
- location-system-api: Provides the information about the currently available or open set of nearby stations, leisure-spots and set of postal codes based on the postal code or station names passed as the query parameter.
- covid-system-api: Retrieves the COVID-19 case details for the provided city.
- weather-system-api: Returns weather forecast for the date and location provided as the query parameters.
Project Setup Prerequisites and Instructions
UI
- Install NodeJs from https://nodejs.org/en/.
- Google Chrome is recommended for better UI experience or any browser with a resolution 2560 x 1600.
- Install Git on to your machine (if not already installed), following the instructions on https://github.com/git-guides/install-git.
- Open Command prompt and change directory to the folder where you want to clone the project into your machine, followed by executing the git command:
git clone https://github.com/smeghakumar/travelzoom.git
.
- Change your directory to the project folder and execute the command:
npm install
.
- Execute the command:
npm start
. This will start the NodeJs front-end application.
- Launch the web browser and enter the locally running application URL http://localhost:4200/.
- MuleSoft Anypoint Platform account for publishing assets and deploying Mule applications.
Note: All the calling points to the external systems have been mocked with the help of a Mule mocking API which replicates the request and response structure similar to the actual service. The URLs for the actual external services are commented in the configuration YAML file. This is because most of them are free only for a month and then requires a subscription for extended usage.
To test from UI please use the below-listed combination of origin-destination location name combinations or equivalent combinations replacing with the provides postal codes:
Location Names
Origin Location | Destination Location |
---|---|
Leeds | London Waterloo |
Woking | Leeds |
Leeds | Basingstoke |
Basingstoke | Leeds |
London Waterloo | London St Pancras (Int) |
London Waterloo | Leeds |
London St Pancras (Int) | Woking |
Basingstoke | Woking |
London St Pancras (Int) | Leeds |
London St Pancras (Int) | London Waterloo |
Postal codes
Location | Postcode | Location | Postcode |
---|---|---|---|
London WaterLoo | SE1 8SW | Basingstoke | RG21 7EB |
London WaterLoo | SE1 8SW | Basingstoke | RG21 7LW |
London WaterLoo | SE1 7RJ | Basingstoke | RG21 7JT |
London WaterLoo | SE1 7RY | Basingstoke | RG21 7DW |
London St Pancras (Intl) | N1C 4 | Basingstoke | RG22 5NZ |
London St Pancras (Intl) | N1C 4QP | Leeds | LS1 6AL |
London St Pancras (Intl) | NW1 2QS | Leeds | LS2 8DZ |
London St Pancras (Intl) | N1C 4AP | Leeds | LS2 7HY |
London St Pancras (Intl) | N1 9NW | Leeds | LS1 1PJ |
Woking | GU21 4LL | Leeds | LS2 7AU |
Woking | GU22 7AE | Woking | GU22 7AA |
Woking | GU21 6XR |
MySQL Database
- Execute the Database scripts for table creation available at https://github.com/smeghakumar/Database-Scripts.git
Conclusion
"If you don't know where you are going. How can you expect to get there?"
Start your journey from the destination before you start from your home. Get all the details of the destination using the TravelZoom and plan the travel accordingly. The collection of API’s brings the information’s to your mobile screen whenever and where ever you wanted.
Future Scope
Future additions in the project pipeline are as follows:
- Integrating with IoT devices and creating an internet-based Smart Home automation system.
- Log externalization to Splunk/ELK
- Advanced error handling, and Incident notification layer for the whole system.
- Integrating more of Everyday APIs.
“You'll never reach perfection because there's always room for improvement. Yet get along the way to perfection, you'll learn to get better.”
Hope the above quote well explains my thoughts on future extension and enhancements to the project.
References
Git Repository Links
- UI Application: https://github.com/smeghakumar/travelzoom.git
- MuleSoft Implementations: https://github.com/smeghakumar/MuleSoft-APIs.git
- RAML Specifications: https://github.com/smeghakumar/RAML.git
- Database Scripts: https://github.com/smeghakumar/Database-Scripts.git
Top comments (4)
Thanks for your submission @meghakumar !
My pleasure, and thank you to the entire MuleSoft team for organizing such an amazing event.
Seems nice concept
Thanks Vikas
Some comments have been hidden by the post's author - find out more