Design a payment system using Django Rest Framework

mustaque ahmed
Nerd For Tech
Published in
4 min readJun 8, 2021

--

In this post, we are going to design a payment system API using Django Rest Framework. Before going ahead, I want you to read about WAL, MVCC in DBMS. You can go through the link as well. By now I'm guessing you have a decent knowledge of what WAL or MVCC is?

Let’s talk about our architecture

This is how our architecture looks like it is not an ideal architecture but the basic one for our easy understanding. In this diagram, we have not added other features like async task queue or caching layer, etc.

Let’s suppose, there are three users in our system User One, User Two, and User Three. User one is trying to make a payment of X amount to User Two.

User One initiates the payment request and it will hit our server passing through the load balancer. At the database level, we will be executing commands in the form of a transactional group. If any of the commands of the group fails it will roll back to its previous state or that particular transaction is not going to happen and the user will receive a notification of the final status of their transaction.

Let’s look at how a single transaction looks like

While transferring money from one account to the other account these operations are going to be performed.

  1. Check if User One is having sufficient balance in his account or not. If yes then we will proceed with the transaction or will raise an error Saying Insufficient Balance.
  2. Next is to subtract X amount from User One account.
  3. Subtract our payment processing fee example: 0.75
  4. Add same X amount to User Two account.

Now if we didn’t encounter any errors then this transaction will commit to the database or else nothing is going into the database.

Let’s Jump into the Implementation part

Before jumping to the actual code implementation let’s quickly summarize what all endpoints we are going to develop or what database is required and so on. For this post, we will be using MySQL as a database.

Backend API endpoints

POST /register
POST /login
GET /balance
POST /balance
POST /transfer

Auth API’s are public endpoints, anyone can access them whereas balance and transfer endpoints are protected endpoints only authenticated users can use them.

Django User Model

Let’s keep our model easy and simple. We’re going to store account_balance in the user model itself. This is how our User model looks like. I realized I forgot to add created_at & updated_at in the User model. Let’s ignore it for now and move ahead.

User Model

Auth API’s

For authentication, we’re using a package called rest_framework_jwt. Using this package we don’t really need to implement login API since it works out of the box. We just need to import the login view and use it.

Login API

For register API, we need to write an API view

Register API View

After auth API’s here comes the most crucial part of our system.

Balance API

Balance API ViewSet

On line number 42 we are calling transaction.atomic as a context manager. You might think while adding balance into our account why are we using transaction. In order to prevent inconsistency if multiple concurrent requests come to the server, we are implementing it as a transaction. This API will serve both the purpose to fetch our account balance or adding money into our account.

Transaction API

In this viewset, we are first checking if the user account balance is sufficient then start the transaction and update it in the database else return the error in response. We are performing 3 operating as a single atomic transaction command. It will ensure atomicity and durability.

Wrapping Up

I hope you’re this article gives you a fair idea of implementing a payment system on a server level. Obviously, this can be improvised further. If there is something wrong with the post. Please let me know. If you want to know the basic implementation of WAL in python. You can go through the code mention here http://web.mit.edu/6.033/2018/wwwdocs/assignments/wal-sys.py

If you’ve made it this far, please consider leaving a comment with your thoughts or suggestions on what could I do differently.

There will be future installments of such posts, so stay tuned!

--

--