Allows user to search flights based on origin, destination and date. My goal for this project was to see how React can work with Rails. APP uses Rails as a backend API and React as frontend. This separates app into two which communicates via API requests. This approach allows you to decouple the frontend and backend enable it to operate independently.
No libraries was used to start with but as project expanded I have tried and implemented different libraries for better coding experience.
For this project I will be using Vite for javascript bundler with React and Sass. I thought about using Vue.js instead of React but I am still learning React so decided to spend more time on it. Sass is my go to CSS as I am more familiar with it and give me more control over tailwind CSS.
Flight information and booking process will be handle by Amadeus API. Amadeus is one of big three flight/travel GDS which provide real time flight information data. The app will be running on test environment which has some limitations as Amadeus provides limited data collections and most uses static cached data in this mode.
Flight Offers Search API
endpoint to search for flights based on users desired criteria.Flight Offers Price API
as airfare fluctuates. During this process you add aditional function like extra bags or legroom can be purchased on top of flight ticket. Flight Create Orders API
. This creates Passenger Name Record, a unique identifier which contains reservation data like passenger information and itinerary details. Note. In this app payment is handle by using Stripe and I have combined the step 3, 4 and 5 into one as I won't be using accredited agents or consolidators.
Access Token: When a user signs in, they receive an accessToken, which is used to authenticate requests to protected resources. This token usually has a short expiration time (e.g., minutes).
Refresh Token: Along with the accessToken, the user also receives a refreshToken. This token is used to obtain a new accessToken when the original one expires without requiring the user to log in again.
Initial Sign-In:
The user provides their credentials, and upon successful sign-in, they receive both an accessToken and a refreshToken.Making Authenticated Requests:
The application uses the accessToken to authenticate requests to the Rails Backend API.Token Expiration:
Once the accessToken expires, the application uses the refreshToken to request a new accessToken.Handling Refresh:
If the refreshToken is valid, the server issues a new accessToken. This can happen seamlessly in the background without requiring the user to log in again.Sign Out:
When the user signs out, the application clears both tokens from storage.
Implementation Steps:Store the refreshToken:
You should store the refreshToken in localStorage (or a more secure method like an HttpOnly cookie) to use it for fetching new accessTokens.Handle Token Refreshing:
Create a function that checks if the accessToken is expired and, if so, uses the refreshToken to get a new one.Call Refresh Token Endpoint:
Implement the API call to the endpoint responsible for refreshing the tokens, which might look something like this:Payment is processed using Stripe specifically stripe element. I first wanted to use stripe-hosted page for payment for simplicity sake but I realise this approach needs pre created product/price on stripe to work. So this approached won't work as there are many flight with varied prices. So I had to go with second option which was to create custom payment flow. Where final price calculate on the server side and push to front end then to stripe.
During testing environment I required Ngrok to allow testing of webhook over https for stripe
Rails API was used to create stripe payment of intent (client_secret
) and React handles the user payment through stripe's confirmPayment
method.
Rails will handle all API request and React will use it to provide Real-time Feedback, eg destination location in flight search.
client
) makes a GET request to the Rails backend.I have decided on this approach instead of React directly making request to external APIs due to security, data processing and error handling.
Amadeus API to grab all flight and travel related information. Including airports, airliner, flight schedule, local activities and more.
OpenCage Geocoder is used for collecting user location data. I could have used IP based location finder but I decided to go with geolocation for possible expansion allowing user to use map to set origin and destiantion.
Restcountries is used to collect related country data from opencage for country language and country flag.
Amadeus Ruby API endpoint
Flight_Offer search is very unstable. Rework was needed to use faraday to make custom API calls.
404 Error with React Routes
Because Rails server doesnt recognize React's client-side routes. I need to create Catch-All
routes for non Rails API routes to serve index.html when routes is not recognised(if page is refreshed while in React Route, Rails won't recognise the route path therefore giving 404 error). This involved few steps as I found out.
Create new controllers to serve and render index.html
.
ApplicationController
inherits from ActionController::API
serving only API requests. StaticBaseController
inherits from ActionController::Base
for rendering HTML viewsStaticController
inherits from StaticBaseController
and renders index.html from /public
as follow:
def index
render file: Rails.root.join('public', 'index.html'), layout: false
end
Create a new route to catch-all routes for React frontend
get '*path', to: 'static#index', constraints: ->(request) { !request.xhr? && request.path.exclude?('/api') }