Home/Blog/System Design/Learn Django RESTFul API using LitRPG tropes
Home/Blog/System Design/Learn Django RESTFul API using LitRPG tropes

Learn Django RESTFul API using LitRPG tropes

13 min read
Nov 06, 2024

Introduction#

Navigating the world of RESTful APIs can be challenging, like wandering through a maze blindly. However, with Django, it’s like having clear signposts at every corner, making the journey effortless.

In this blog, we will first understand the basics of RESTful APIs, then move to a fun and unique problem, create some APIs, and test them. Interested? So, what are you waiting for? Let’s dive in.

The project#

The phenomenon of anime and LitRPG, a subgenre of sci-fi and fantasy, has swept across the globe. LitRPG has gained popularity among both readers and writers due to its unique fusion of gaming elements and captivating storytelling. In my spare time, I write novels in a couple of LitRPG series under a penname. Inspired by my love for LitRPG, I set out to create a project that will assist readers and writers in delving into the extensive universe of LitRPG tropes. In this blog post, join me as I take you on a journey on using Django and the Django Rest Framework to develop a LitRPG trope API.

Introduction to RESTful APIs#

To set the background, in this section, I'll start by first explaining REST and then move on to explain what RESTful APIs are.

Principles of Representational State Transfer (REST)#

The principles of Representational State Transfer (REST) are a set of architectural constraints that guide the design and implementation of RESTful APIs. These principles are as follows:

  1. Client-server architecture: The client and server are separate, with the client making requests to the server to access or modify resources.

  2. Stateless: The server does not maintain any information about the client state between requests. Each request contains all the information necessary to fulfill that request.

  3. Cacheable: Responses from the server can be cached by the client to reduce the number of requests made to the server.

  4. Uniform interface: A uniform interface is used to communicate between client and server, including the use of HTTP methods (GET, POST, PUT, DELETE), HTTP status codes, and standard HTTP headers.

  5. Layered system: The architecture is designed as a layered system, with each layer being responsible for a specific function, such as authentication or encryption.

  6. Code on demand (optional): In some cases, the server may provide code to the client, such as JavaScript, to execute on the client side.

These principles work together to create a scalable, flexible, and maintainable architecture for building web services and APIs. By following these principles, developers can create RESTful APIs that are easy to use, efficient, and scalable. Let’s first define them.

What is a RESTful API?#

RESTful API, also referred to as RESTful web service, is an architectural style for networked application design. The concept revolves around resources, which are recognized by URIs and can be manipulated using a defined set of actions. RESTful APIs are built to be stateless, so each request includes all the required information to complete it, without depending on stored context or session data. The API’s scalability and flexibility are enhanced, as it enables communication between different devices and applications without the requirement of a persistent connection. RESTful APIs commonly employ HTTP methods like GET, POST, PUT, and DELETE to manipulate resources, ensuring simplicity in comprehension and implementation. Due to their simplicity, flexibility, and scalability, RESTful APIs have become a popular choice for building web services and microservices.

Uniform Resource Locators (URLs) are used to identify and address resources uniquely in a RESTful API, which can include data objects, services, or abstract concepts. The use of a unique URL ensures that each resource has a specific identifier for locating and accessing it. Clients can easily request and interact with resources in a consistent and predictable way across various systems and applications using this URL-based representation.

Key ideas#
Statelessness#

The key principle of RESTful APIs is their statelessness, wherein the server doesn’t store the client state or remember previous requests. In each request, the client provides all the information required for the server to fulfill it. By using this approach, the server stays oblivious to the client’s context and treats each request independently. Consequently, the server becomes more efficient at handling requests, while clients take on the responsibility of managing their own state, resulting in a system that is more scalable, flexible, and fault-tolerant.

While we often highlight the advantages of a stateless architecture—such as scalability and simplicity—it’s crucial to address the challenges posed by stateful systems. In a stateful architecture, different clients may operate on their own data snapshots, leading to potential inconsistencies when the state changes. In contrast, a stateless architecture, like REST, ensures that each request is independent and retrieves the most current data from the server. This design enhances the reliability of the information being processed and simplifies the overall system architecture, making it easier to manage and scale. By acknowledging the importance of data coherence, we can better appreciate the significance of statelessness in modern application design.

Key principles
Key principles
Uniform interface#

Developers find it easy to comprehend and interact with RESTful APIs because of their consistent use of conventions. Established patterns and protocols make it easy for developers to grasp the intuitive and predictable usage of APIs. By maintaining consistency, developers can write code that is reusable across different APIs, resulting in higher productivity and a reduced learning curve. This leads to increased accessibility of APIs, allowing developers to concentrate on creating innovative applications instead of grappling with the complexities of each API.

Resource-based#

The central entities in a RESTful API are the resources, and clients interact with them through CRUD operations. Clients can perform various operations on resources, such as creating, reading, updating, and deleting them. With the CRUD-based interaction model, clients can easily manipulate resources and build/consume RESTful APIs in a straightforward and intuitive manner. By emphasizing resources and CRUD operations, developers can build APIs that are easily maintained, scalable, and adaptable.

Hypermedia as the engine of application state (HATEOAS)#

A crucial aspect of RESTful APIs is their ability to provide links to related resources, giving clients the opportunity to navigate and uncover new resources. It is commonly referred to as “hypermedia” or “HATEOAS” (Hypermedia as the engine of application state). Including links to related resources in API responses enables clients to explore the API and access extra information without knowing the specific URLs beforehand. This allows for a flexible and dynamic interaction with the API, where clients can explore new resources and navigate according to their specific requirements.

API system design: Project idea#

The API was designed with a simple idea in mind: build a database that catalogs LitRPG tropes, subgenres, and relevant details, and make it accessible to users through a RESTful API. This would allow readers and writers to explore the world of LitRPG, discover new tropes, and even build their own projects on top of the API.

You could say that this blog post is about two contrasting forms of love. I find joy in both exploring Django’s simplicity and power and immersing myself in the world of LitRPG novels and anime.

I had the idea that it would be wonderful if we could figure out a solution for building RESTful APIs using Django. It would be even more exciting if we employ it to discover fascinating data about the genre I love. i.e. LitRPG or anime.

Anime credit: Bing Designer
Anime credit: Bing Designer
Understanding tropes#

Tropes in novels are repetitive themes, motifs, or clichés frequently seen in storytelling. They act as recognizable patterns to swiftly communicate ideas, emotions, or character traits to the audience. Although tropes can be viewed as cliché or predictable, they can also serve as powerful tools for writers when used creatively or subverted.

The LitRPG genre, which blends traditional literature with role-playing game mechanics, often features several common tropes. To enhance comprehension of the problem domain, here are a few typical tropes in LitRPG, accompanied by examples:

Leveling up: Characters gain experience points (XP) and level up, becoming stronger and more capable.

Example: In "Awaken Online" by Travis Bagwell, the protagonist Jason levels up his character through various quests and battles, gaining new skills and abilities as he progresses.

Other examples of tropes include:

- Game Mechanics
- The Chosen One
- Guilds and Parties
- NPCs with Depth
- Real-Life Consequences
- Overpowered Protagonist (OP)

These tropes help define the LitRPG genre and create a familiar framework for readers. They also allow authors to explore unique narratives and character development within that framework.

Subgenres of LitRPG#

As we have discussed, LitRPG blends elements of traditional storytelling with the mechanics and themes of role-playing games, but that is not all. Within LitRPG, over time, several subgenres have emerged, each with its own unique characteristics and focus. Here are some notable subgenres of LitRPG:

Progression fantasy#

This subgenre emphasizes character growth and development through leveling up, acquiring new skills, and overcoming challenges. The focus is often on the protagonist’s journey from a novice to a powerful figure.

Example

“The Land” series by Aleron Kong showcases a protagonist who levels up and gains new abilities while navigating a richly developed fantasy world.

An armored hero fighting a fire-breathing dragon—image credit: Bing designer
An armored hero fighting a fire-breathing dragon—image credit: Bing designer

Some of the other subgenres include:

  • Survival RPG

  • GameLit

  • Virtual Reality (VR) LitRPG

  • Dungeon Crawler

  • Slice of Life RPG

  • Isekai LitRPG

  • Comedy LitRPG

These subgenres allow authors to explore various themes and storytelling techniques within the LitRPG framework, catering to a wide range of reader preferences and interests. Each subgenre offers a unique take on the intersection of gaming and narrative, enriching the overall landscape of LitRPG literature.

Divide and rule method
Divide and rule method

Now that we have an understanding of the problem domain, to get started, let’s break down the process into smaller, manageable chunks. Here’s a high-level overview of the steps we can follow:

  1. Set up a new Django project: We’ll create a new Django project using the django-admin command. This will give us a basic directory structure and the necessary files to get started.

  2. Define the API’s scope and requirements: We’ll identify the resources we want to expose through the API, the actions that can be performed on those resources, and the data models required to support those actions.

  3. Create the necessary models: We’ll define the data models using Django’s ORM (Object-Relational Mapping) system. This will involve creating models for the resources we identified in Step 2.

  4. Create the API views: We’ll create views that will handle incoming requests, perform the necessary actions, and return responses in a format that’s suitable for a RESTful API (e.g., JSON).

  5. Define the API endpoints: We’ll define the URLs that will map to our views using Django’s URL dispatcher.

  6. Implement authentication and authorization: We’ll add authentication and authorization mechanisms to ensure that only authorized users can access the API.

  7. Test the API: We’ll write tests to ensure that the API is working as expected.

Let’s start with Step 1. To create a new Django project, let’s execute the following command in our terminal:

This will create a new directory called restful_api_project with the basic structure for a Django project.

django-admin startproject restful_api_project

Next, let’s move into the project directory and create a new app for our API:

This will create a new directory called api with the basic structure for a Django app.

Now that our project and app are set up, we can start defining the scope and requirements of our API. Please note that in some cases (such as on the Mac), you might instead need to use the python3 command.

cd restful_api_project
python manage.py startapp api

Let’s make sure Django knows this app exists. So, we’ll make a few changes.

In the subdirectory restful_api_project, we can edit settings.py to change the INSTALLED_APPS to look like the following:

INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"api.apps.ApiConfig",
]

Note that we have added a new item. api.apps.ApiConfig.

Let’s create an API that provides a list of tropes in top LitRPG novels, allowing users to query by partial name and retrieve details for subgenres like Isekai, Cultivation, and more.

Step 2: Define the API’s scope and requirements

For this API, we’ll focus on providing the following information:

  • A list of tropes in top LitRPG novels

  • Ability to query by partial name

  • Details for subgenres (e.g., Isekai, Cultivation)

  • Additional information about each trope, such as a brief description, examples, and related tropes (Optional)

Step 3: Create the necessary models

In Django, we’ll create two models: Trope and SubGenre. Create a new file models.py in the api app directory:

# api/models.py
from django.db import models
class SubGenre(models.Model):
name = models.CharField(max_length=50, unique=True)
description = models.TextField(blank=True)
def __str__(self):
return self.name
class Trope(models.Model):
name = models.CharField(max_length=100, unique=True)
description = models.TextField(blank=True)
sub_genre = models.ForeignKey(SubGenre, on_delete=models.CASCADE, related_name='tropes')
examples = models.TextField(blank=True)
def __str__(self):
return self.name

Here, we’ve defined a SubGenre model to store the subgenre names and descriptions, and a Trope model to store the trope names, descriptions, and relationships with subgenres.Let's also run makemigrations.

Let's also run makemigrations.

python manage.py makemigrations
python manage.py migrate

Step 4: Create the API views

Now that we are done with the models, we need to do something about the views. So, let's create a new file views.py in the api app directory:

# api/views.py
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import Trope, SubGenre
from .serializers import TropeSerializer, SubGenreSerializer
class TropeListView(APIView):
def get(self, request):
tropes = Trope.objects.all()
serializer = TropeSerializer(tropes, many=True)
return Response(serializer.data)
class TropeDetailView(APIView):
def get(self, request, pk):
trope = Trope.objects.get(pk=pk)
serializer = TropeSerializer(trope)
return Response(serializer.data)
class SubGenreListView(APIView):
def get(self, request):
sub_genres = SubGenre.objects.all()
serializer = SubGenreSerializer(sub_genres, many=True)
return Response(serializer.data)
class SubGenreDetailView(APIView):
def get(self, request, pk):
sub_genre = SubGenre.objects.get(pk=pk)
serializer = SubGenreSerializer(sub_genre)
return Response(serializer.data)
class TropeSearchView(APIView):
def get(self, request):
query = request.GET.get('q')
tropes = Trope.objects.filter(name__icontains=query)
serializer = TropeSerializer(tropes, many=True)
return Response(serializer.data)

Here, we’ve defined five views:

  • TropeListView: This returns a list of all tropes.

  • TropeDetailView: This returns detailed information for a specific trope.

  • SubGenreListView: This returns a list of all subgenres.

  • SubGenreDetailView: This returns detailed information for a specific subgenre.

  • TropeSearchView: This returns a list of tropes that match the partial name query.

Step 5: Create serializers

That wasn't too bad, right? We can move forward now and create a new file serializers.py in the api app directory:

# api/serializers.py
from rest_framework import serializers
from .models import Trope, SubGenre
class TropeSerializer(serializers.ModelSerializer):
class Meta:
model = Trope
fields = ['id', 'name', 'description', 'sub_genre', 'examples']
class SubGenreSerializer(serializers.ModelSerializer):
class Meta:
model = SubGenre
fields = ['id', 'name', 'description']

Here, we’ve defined two serializers: TropeSerializer and SubGenreSerializer, which will convert the Trope and SubGenre model instances to JSONJSON, which stands for JavaScript Object Notation, is a lightweight data interchange format that is easy for humans to read and write and easy for machines to parse and generate. It is primarily used to transmit data between a server and a web application as an alternative to XML. data.

Step 6: Define API endpoints

Create a new file urls.py in the api app directory:

# api/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('tropes/', views.TropeListView.as_view()),
path('tropes/<int:pk>/', views.TropeDetailView.as_view()),
path('sub-genres/', views.SubGenreListView.as_view()),
path('sub-genres/<int:pk>/', views.SubGenreDetailView.as_view()),
path('search/', views.TropeSearchView.as_view()),
]

Here, we’ve defined the API endpoints for the views we created earlier.

That’s it! We’ve set up the basic structure for our API. Now, let’s create some sample data and test the API.

Create sample data

Open the Django shell by running python manage.py shell in your terminal. Then, create some sample data:

# Import the models
from api.models import SubGenre, Trope
# Create SubGenres
lit_rpg = SubGenre.objects.create(name='LitRPG', description='Literature that incorporates role-playing game mechanics into the narrative.')
progression_fantasy = SubGenre.objects.create(name='Progression Fantasy', description='Focuses on character growth and development through leveling up and acquiring new skills.')
survival_rpg = SubGenre.objects.create(name='Survival RPG', description='Characters must survive in a hostile environment, facing threats from monsters and other players.')
gamelit = SubGenre.objects.create(name='GameLit', description='Emphasizes the narrative aspects of gaming, incorporating game mechanics into the story.')
vr_litrpg = SubGenre.objects.create(name='Virtual Reality LitRPG', description='Set in fully immersive virtual reality environments where characters interact with the game world as if it were real.')
dungeon_crawler = SubGenre.objects.create(name='Dungeon Crawler', description='Focuses on exploring dungeons, battling monsters, and collecting loot.')
isekai_litrpg = SubGenre.objects.create(name='Isekai LitRPG', description='Involves characters being transported to a different world with RPG elements.')
comedy_litrpg = SubGenre.objects.create(name='Comedy LitRPG', description='Incorporates humor and satire into the LitRPG framework.')
# Create tropes for LitRPG
Trope.objects.create(
name='Leveling Up',
description='Characters gain experience points (XP) and level up, becoming stronger and more capable.',
sub_genre=lit_rpg,
examples='In "Awaken Online" by Travis Bagwell, the protagonist, Jason, levels up his character through various quests and battles, gaining new skills and abilities as he progresses.'
)
Trope.objects.create(
name='Game Mechanics',
description='The story often includes detailed descriptions of game mechanics, such as stats, skills, and inventory systems.',
sub_genre=lit_rpg,
examples='In "The Land" series by Aleron Kong, the protagonist, Richter, frequently checks his character sheet, which displays his stats, skills, and inventory, allowing readers to understand his growth and choices.'
)
Trope.objects.create(
name='The Chosen One',
description='The protagonist is often portrayed as a special character destined for greatness, often with unique abilities or a significant role in the game\'s world.',
sub_genre=lit_rpg,
examples='In "Sufficiently Advanced Magic" by Andrew Rowe, the main character, who possesses unique magical abilities, is thrust into a world where he must fulfill a significant role in the unfolding events.'
)
Trope.objects.create(
name='Guilds and Parties',
description='Characters often form groups or guilds to tackle challenges together, emphasizing teamwork and camaraderie.',
sub_genre=lit_rpg,
examples='In "Play to Live" by D. Rus, the protagonist joins a guild to survive and thrive in a deadly virtual world, highlighting the importance of collaboration and strategy.'
)
Trope.objects.create(
name='NPCs with Depth',
description='Non-player characters (NPCs) are often given more depth and personality, sometimes becoming allies or important figures in the story.',
sub_genre=lit_rpg,
examples='In "The Land: Founding" by Aleron Kong, NPCs are not just background characters; they have their own stories, motivations, and can even evolve alongside the protagonist.'
)
Trope.objects.create(
name='Real-Life Consequences',
description='Actions taken in the game world can have real-life repercussions, adding stakes to the gameplay.',
sub_genre=lit_rpg,
examples='In "Awaken Online," the protagonist\'s actions in the game can affect his real-life situation, creating tension and urgency in his decisions.'
)
Trope.objects.create(
name='Overpowered Protagonist (OP)',
description='The main character often becomes exceptionally powerful, sometimes to the point of being invincible.',
sub_genre=lit_rpg,
examples='In "The Beginning After the End" by TurtleMe, the protagonist reincarnates into a fantasy world with immense power, allowing him to overcome challenges that would be insurmountable for ordinary characters.'
)
# Create tropes for Progression Fantasy
Trope.objects.create(
name='Progression Fantasy',
description='Focuses on character growth and development through leveling up and acquiring new skills.',
sub_genre=progression_fantasy,
examples='The "Land" series by Aleron Kong showcases a protagonist who levels up and gains new abilities while navigating a richly developed fantasy world.'
)
# Create tropes for Survival RPG
Trope.objects.create(
name='Survival RPG',
description='Characters must survive in a hostile environment, facing threats from monsters and other players.',
sub_genre=survival_rpg,
examples='In "Play to Live" by D. Rus, the protagonist must navigate a deadly virtual world where survival is paramount, and every decision can mean the difference between life and death.'
)
# Create tropes for GameLit
Trope.objects.create(
name='GameLit',
description='Focuses on the narrative aspects of gaming, incorporating game mechanics into the story.',
sub_genre=gamelit,
examples='In "Awaken Online" by Travis Bagwell, traditional storytelling blends with game mechanics, allowing readers to experience the protagonist\'s journey through a virtual world.'
)
# Create tropes for Virtual Reality LitRPG
Trope.objects.create(
name='Virtual Reality LitRPG',
description='Set in fully immersive virtual reality environments where characters interact with the game world as if it were real.',
sub_genre=vr_litrpg,
examples='In "Sword Art Online" by Reki Kawahara, characters are trapped in a VR game, where they must navigate challenges and fight for their lives to escape.'
)
# Create tropes for Dungeon Crawler
Trope.objects.create(
name='Dungeon Crawler',
description='Focuses on exploring dungeons, battling monsters, and collecting loot.',
sub_genre=dungeon_crawler,
examples='The "Dungeon Crawler Carl" series by Matt Dinniman follows the adventures of a character navigating a dangerous dungeon filled with monsters and traps.'
)
# Create tropes for Isekai LitRPG
Trope.objects.create(
name='Isekai LitRPG',
description='Involves characters being transported to a different world with RPG elements.',
sub_genre=isekai_litrpg,
examples='In "Re:Zero - Starting Life in Another World" by Tappei Nagatsuki, the protagonist is transported to a fantasy world and must navigate its challenges while utilizing his unique ability to return from death.'
)
# Create tropes for Comedy LitRPG
Trope.objects.create(
name='Comedy LitRPG',
description='Incorporates humor and satire into the LitRPG framework.',
sub_genre=comedy_litrpg,
examples='"Awaken Online: Catharsis" by Travis Bagwell includes comedic elements and humorous situations that arise from the protagonist\'s interactions with the game world and its mechanics.'
)
print("Sample data created successfully!")

Test the API

Open a new terminal window and run python manage.py runserver to start the Django development server. Then, use a tool like curl or a REST client like Postman to test the API.

For example, to get the list of all tropes, run the following command:

curl http://localhost:8000/api/tropes/

This should return a JSON response with the list of tropes.

To search for tropes by partial name, run the following command:

curl "http://localhost:8000/api/search/?q=overpowered"

The reason for using a quotation mark is to ensure the shell doesn’t misinterpret the ? character. Another option is to use the \ backslash before the ? character to bypass it.

So, hopefully, if you have been following all the steps until now, this should return a JSON response with the list of tropes that match the partial name query.

That’s it! We’ve created a basic API for LitRPG tropes. Amazing right?

Conclusion#

In conclusion, this blog provides a comprehensive guide to creating a RESTful API using Django, specifically tailored for managing and querying LitRPG tropes and subgenres. It begins with an introduction to RESTful APIs, outlining their fundamental principles, such as client-server architecture, statelessness, cacheability, and the use of a uniform interface. Then, we delved into the specifics of the project, detailing the steps required to set up a Django project, define the API's scope, create necessary models, and implement views and serializers.

The API is designed to allow users to access a list of tropes from popular LitRPG novels, search by partial names, and retrieve detailed information about various subgenres. By following the outlined steps, readers can successfully build a functional API that enriches the understanding of LitRPG literature and provides a platform for further exploration of its themes and storytelling techniques. It is important to test the API extensively to verify that it aligns with the intended requirements and performs as planned. Crafting a customized API that suits your specific needs can help broaden your knowledge.

Frequently Asked Questions

What is a RESTful API, and why is it important?

  • A RESTful API (Representational State Transfer API) is an architectural style for designing networked applications.
  • It allows different systems to communicate over the web using standard HTTP methods (GET, POST, PUT, DELETE) to manipulate resources. RESTful APIs are important because they provide a simple, scalable, and flexible way to interact with web services, making it easier for developers to build and integrate applications.

How does Django facilitate the creation of RESTful APIs?

What are some common tropes found in LitRPG literature that were used in this project?

How can we test the RESTful API once it’s built?

Outline the steps involved in creating a RESTful API for LitRPG tropes using Django.

To learn more about Python, Django, and API/System design, please check out the resources below:


 
Join 2.5 million developers at
Explore the catalog

Free Resources