Basic API Development Part 2 - Creating a simpe movie ticket reservation system

Prologue


 

Many of us at some point in our lives have eagerly waited for our favourite movie be it a new Harry Potter movie or a new Avengers movie, and the moment the tickets go out on sale all it takes is a few clicks on Paytm or BookMyShow to get the tickets to our favourite cinema hall be it INOX, PVR, etc.
So what's happening here? Paytm and BookMyShow do not own any multiplexes so how are they providing the facility of booking tickets to a third party player and that too in real-time.
The answer: APIs 

API: Connecting consumers to service providers

So what's happening here is that the good folks at PVR (or INOX etc.) have developed there own ticket booking software solutions, let's call this a resource, and they are allowing platforms like Paytm and BookMyShow to access this resource through an interface. This interface is called an API (Application Programming Interface).  
There are various APIs in existence providing services ranging from navigation and earthquake data to video download and motivational quotes generator.

Let's Create A Simple Movie Ticket Reservation System

Now that we know what an API is and what are its real-world applications lets dive deeper and create our own API for a simple Movie Ticket Reservation System.
To understand the basic architecture and design ideology behind APIs (RESTful APIs in particular) you may go through Basic API Development Part 1 - Importance, Theory and Hands-on with flask framework

So let's go through our problem statement and look at what we would be aiming to develop. 
Problem Statement: Develop a Movie ticket reservation API which has the following functionalities:
  • Add details of a screen (total number of seats, aisle seats).
  • Get the number of seats available for a particular screen.
  • Get information about a particular seat number at a given screen.
  • Reserve one or multiple available seats
By screen, we mean a single cinema hall eg: PVR_Allahabad is a screen while PVR_Lucknow is another screen. Also for the sake of simplicity and without loss of generality, we assume that only one show is scheduled on a single day.

Let's  Get To The Juicy Stuff!

Without further adieu let's get to developing our API. We would be using the Flask framework of python to achieve our tasks. Why Flask you ask, because with Flask we can get up and running with our application in no time with very few low-level configurations to make. The following code shows how easy it is to spin up a server in Flask. 
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
if __name__ == '__main__':
app.run(host='localhost', port=8080)
Now open your favourite browser and type http://localhost:8080 and you will be greeted with 'Hello, World!'

Creating our Development Environment

Ticket_Booking
├── api
├── requirements.txt
├── README
└── venv
├── run.py
  • Ticket_Booking is our root directory and contains all the project related codes, configurations and environments. It contains two sub-directories api and venv.  
  • The 'api' directory contains all the source code related to our API and 'venv'  is the virtual environment for the project. 
  • The 'run.py' file is the main file which is executed first whenever the application is started. 
  • In addition to this we have two other files 'README' and 'requirements.txt' which we need not worry about now.
It's a good practice to create a virtual environment for our project rather than using the global environment. To learn how to create a virtual environment in python click here.

Activate the virtual environment using the command
$ source venv/bin/activate

Install Flask using pip 
$ pip install Flask

Now we need to initialize our app and databases. To do this change into 'api' directory and create three files

  • __init__.py  - Initialises our app and databases
  • models.py - contains the classes/models for our database
  • routes.py - contains the endpoints of our API.
The contents of the __init__.py file are as shown:

Create the database models in the 'models.py' file

Before we proceed let's first examine the importance of  'models.py' file. We are using SQLite as our database and all relations (tables) are made in SQLite. We can access these tables in two ways
  • either by directly passing SQL queries to the database-engine or
  • in an Object-oriented way using objects and methods, in which case the mapping of the database tables and objects used to access those tables is taken care of by a wrapper library.
We will be using the second method as it is more elegant and allows our database schema to grow and evolve in a decoupled way thus maintaining code integrity. This is an example of ORM (Object-Relational Mapper) model.

The classes defined in 'models.py' are mapped to tables in the database and this mapping is provided by SQLAlchemy which is a wrapper library.  SQLAlchemy also converts object method invocations (used to access or modify tables) into SQL queries and passes them onto the database engine. It also maps the results of the queries into objects and returns them to the calling method.

Now that our app is initialized and our database is set, we have reached the stage from where we can start writing our API end-points.

Defining the endpoints of our API

Our API will have three endpoints:
  • /screens  - Add new screen and screen details. This endpoint will use the HTTP POST method to add a new screen using data in JSON format in the request body.
  • /screens/<screen_name>/seats - Get information about a seat or number of reserved/unreserved seats. This endpoint uses the HTTP GET method.
  • /screens/<screen_name>/reserve - Reserve seats at a given screen identified by screen_name. The details of the seats to be reserved are provided in the request body in JSON format. This endpoint also uses the HTTP POST method.
GET and POST are HTTP methods. HTTP defines a set of request methods to indicate the desired action to be performed for a given resource.
  • GET - The GET method requests a representation of the specified resource. Requests using GET should only retrieve data.
  • POST -  The POST method is used to submit an entity to the specified resource, often causing a change in state on the server (eg: change in the database, etc.)
There are various other HTTP methods like HEAD, DELETE, PUT, etc. but this is all you need to know about HTTP methods to proceed further.

1. Adding a new screen - /screens 

The purpose of this endpoint is to add a new screen and its details. Suppose a new INOX opens up in your neighbourhood then the developers at INOX would use this end-point to add the details of this new screen in their database.

Since we would be hosting our API on localhost the URL for this endpoint: http://locahost:8080/screens
The name of the screen and the data about the number of seats will be sent in JSON format in the request body.
An example would look like:
{
    "name": "inox",
    "seatInfo": {
        "A": {
            "numberOfSeats": 10,
            "aisleSeats": [
                0,
                5,
                6,
                9
            ]
        },
        "B": {
            "numberOfSeats": 15,
            "aisleSeats": [
                0,
                7,
                8,
                14
            ]
        },
        "C": {
            "numberOfSeats": 20,
            "aisleSeats": [
                0,
                9,
                10,
                19
            ]
        }
    }
}

The above JSON object contains data about 'inox'. There are three rows A, B and C with 10, 15 and 20 seats respectively, and the seat number of the aisle seats in given as a list for each respective row.

To handle this request add the following code in 'routes.py' file.


  • @app.route('/screens', methods=['POST'])  : Specifies that whenever a POST request arrives at /screens end-point execute the subsequent method. 
  • The 'request' object is created and passed to the function by Flask and contains the HTTP request received by the endpoint. 
  • Now we extract 'name' of the screen and 'seat_info' from the message body using their respective keys as defined in the JSON object. 
  • A Screen object is created and added to the database and subsequently, details about each of its rows are stored in a Row object and committed to the database.

After successful operation, a success message is returned to the user in the form of a JSON object. For this purpose, we use the 'jsonify' class. This class creates a 'Response' object with the JSON representation of the given arguments with an 'application/json' mime-type. The arguments to this function are the same as to the dict constructor. The 'Response' object is the counter-part of 'request' object.

Voila! That's all the code we need to create an API end-point.

Now that we have our 1st end-point we can test it on Postman.

Testing  /screens end-point on Postman

After sending the request we receive a success message (bottom pane) indicating that our '/screens' API end-point works well and good.

 

2. Viewing information of reserved/unreserved seats - /screens/<screen_name>/seats 

This end-point will have two functions depending on the parameters we send with it. 
  1. Retrieve data about all unreserved seats at a screen. The parameter used is 'status' with possible values 'reserved' and 'unreserved'. Eg. 'http://localhost:8080/screens/inox/seats?status=unreserved'
  2. Retrieve the availability of a number of seats in the vicinity of a given seat. For example, get the status of 4 seats in the vicinity of seat no. B4. This will return whether 4 seats around seat no. 4 in row B are available or not. Eg: 'http://localhost:8080/screens/inox/seats?numseats=4&choice=B4'
URL parameters are widely used and can be seen almost everywhere. The most common place being a google search query. A typical Google search query looks like 
Here: 
  • www.google.com is the resource locator.
  • /search is a resource endpoint.
  • ? denotes the start of URL parameters, after which are numerous parameters in the form of key-value pairs separated by &.
While writing the previous end-point we used the POST method and passed the data as a JSON object in the request body. Now that we want to retrieve data that requires no change in the state of server we will use GET method and pass parameters in the URL to specify what we require. Observe that the parameters can be passed as key-value pairs. The '?' is followed by parameters and multiple parameters are separated by '&'.

To handle this end-point add the following code in 'routes.py' file.

Now that we have the code to handle all requests to this endpoint let's test it.

All unreserved seats at a screen named 'pvr'

Postman makes it easy to set URL parameters as shown in the above picture. To add parameters go to the 'Params' tab and add the required parameters as key-value pairs. The parameters will be automatically formatted into the URL when Postman will send the request

3. Reserving seats at a screen

This end-point uses POST method as the reserved seats have to be marked in the database thus changing the state of the server. The request body contains the information of the seats to be reserved in JSON format.

To handle this request add the following code to 'routes.py' file.

The code is pretty straight-forward and now that we have our end-point let's test it on Postman.
Reserving seats at 'pvr'


And that's it, that's all the code you need to make a simple yet effective and working API. 

Epilogue

We saw how we can use different HTTP methods to specify the nature of the request we want to make and how to pass parameters in the URL to further narrow down our request span. We also saw how to pass JSON objects as data in the body of POST requests. This method can be used to not only pass JSON objects but also raw XML, HTML, etc.

The above implementation of a simple Movie Ticket Reservation System is in essence how all APIs are structured and developed. Other aspects of API development like authorisations, caching, etc. will be covered in subsequent posts.

The Ticketing system we just developed was the sole problem statement in the 2020 recruitment process of Udaan (a unicorn startup based out of Bengaluru, India). The above code snippets are part of the solution which was selected for further rounds of the recruitment process.

Feel free to comment in case of any queries. We would also love to hear any suggestions from you about any future posts you would like to see or any improvements you would suggest in the content. If you enjoyed the content, do subscribe and share, and spread the love. 

Comments

  1. This comment has been removed by the author.

    ReplyDelete
  2. Very Nice blog.

    The most trusted and reputable Movie Ticket Booking API Provider company Softcare Infotech in India providing all type of API services at economical rates. Softcare Infotech is one of the best online movie ticket booking API provider company in India. For more information just visit our website.

    ReplyDelete

Post a Comment