How to Create an URL Shortener with React, Django REST Framework, and SQLite Database
In this article, we will learn to create a custom URL (Uniform Resource Locator) shortener service. The URL shortener will take in a long URL and provide an equivalent short URL suitable for posting on social media and sharing with friends. <!--more--> The shortener service will be made up of 3 parts:
- The front-end for interacting with the client (we will build the front-end using React.js).
- The backend for creating the server, and providing the API routes (we will build the backend using Django REST Framework).
- The database for storing the data (we will use SQLite database).
The user will copy a url, paste it in the input field provided and click the shorten
button. The url will be sent to the backend using the Fetch API
, and the backend will apply a procedure to provide an equivalent short 6-digit url.
An equivalent URL means that the short URL will redirect the user to the same page as the long URL.
Pre-requisites
To follow along, the reader should have:
- Understanding of the Django REST framework.
- Understanding of Serializers in Django REST framework.
- Basic understanding of the React hooks.
- Understanding of the Fetch API.
- Python and Node.js installed on the computer.
- A browser (preferably Google Chrome).
- A code editor (preferably VS Code).
Goals
By the end of this article, the reader should be able to:
- Create a custom URL shortener.
- Work with React and Django.
- Fetch data from a database using Django and display it on React webpage.
Setting up the backend and exposing the API routes
Create a folder named react-drf-shortener
and navigate into it.
First, create a virtual environment for the Django backend.
More information about Django virtual environments can be found here.
Run the commands below in the terminal to create the virtual environment, activate it, and install Django in it:
python -m venv shortener-env
.\shortener-env\Scripts\activate
python -m pip install Django
After Django is successfully installed, run the following commands in the same directory to create a Django project named urlshortener
and open the folder in VS Code:
django-admin startproject urlshortener
Open the integrated terminal in the code editor and ensure that the virtual environment is still active. If not, run the following commands to activate it:
cd ..
.\shortener-env\Scripts\activate
cd urlshortener
The above commands change our active directory to the root directory, activate the virtual environment, and then navigate to the urlshortener
folder.
Run the following code to make sure that the server is working:
python manage.py runserver
If the server is working perfectly, this will open a development server at http://127.0.0.1:8000/
.
Now that the server is working perfectly, we will create a new app to handle all the API requests from the front end as shown below:
django-admin startapp api
Next, run the commands below to install all the packages/dependencies we will need:
pip install djangorestframework
python -m pip install django-cors-headers
The above code does the following:
pip install djangorestframework
will install Django Rest Framework (DRF). DRF allows us to create an API using Django.python -m pip install django-cors-headers
will install CORS to allow the Django backend to communicate with the React front-end.
Registering the API and the installed packages
Open the settings.py
file and modify its contents as shown below:
For the INSTALLED_APPS
section:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'api.apps.ApiConfig', #registers our api app
'rest_framework',
'corsheaders'
]
The INSTALLED_APPS
section holds the names of all Django applications that are activated in this particular Django instance.
In this section, we add:
api.apps.ApiConfig
- This registers the API app that we created earlier.rest_framework
andcorsheaders
- This registers the modules that we installed usingpip
.
For the MIDDLEWARE
section:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
"corsheaders.middleware.CorsMiddleware",
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
The MIDDLEWARE
section is a framework of hooks into Django’s request/response processing. It is a "plugin" system for globally altering Django's input or output.
In the above code, we have added corsheaders.middleware.CorsMiddleware
to listen in on responses.
Append the following code to the settings.py
file:
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
"http://127.0.0.1:3000",
]
The above code specifies the clients that communicate with the Django backend.
Open the urls.py
file in the urlshortener
folder and modify it as shown below to route all the requests to the api
app that we previously created.
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('api.urls')),
]
Working on the API app
Creating the model
Open the models.py
file in the api
folder and modify it as shown below:
from django.db import models
class urlShortener(models.Model):
longurl = models.CharField(max_length=255)
shorturl = models.CharField(max_length=10)
def __str__(self):
return self.shorturl
The above code will create a table in the database with two fields:
longurl
- to store the long URL submitted by the user from the front-end.shorturl
- to store the short URL equivalent of the long URL generated by the server.
Run the commands below to propagate the changes made to the model into the database schema:
python manage.py makemigrations
python manage.py migrate
Creating the serializer
In the app
folder, create a serializers.py
file and modify it as shown below:
from rest_framework.serializers import ModelSerializer
from .models import urlShortener
class urlShortenerSerializer(ModelSerializer):
class Meta:
model = urlShortener
fields = '__all__
The above code will serialize all fields in the urlShortener
model.
More information about Serializers can be found here.
Working on the views
A view is a function in Python that takes in a request from the client and returns a response. The view contains all the required logic to return the response.
To learn more about views in Django, click here.
Open the views.py
file and modify it as shown below:
from django.shortcuts import redirect
from rest_framework.response import Response
from rest_framework.decorators import api_view
from .models import urlShortener
from .serializers import urlShortenerSerializer
import random
@api_view(['POST'])
def makeshorturl(request):
data = request.data
s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!*^$-_"
shorturl = ("".join(random.sample(s, 6)))
urlShortener.objects.create(
longurl=data['longurl'],
shorturl=shorturl
)
longurl = data['longurl']
shorturl = "http://localhost:8000/"+shorturl
return Response({'longurl': longurl, 'shorturl': shorturl})
def redirectUrl(request, shorturl):
try:
obj = urlShortener.objects.get(shorturl=shorturl)
except urlShortener.DoesNotExist:
obj = None
if obj is not None:
return redirect(obj.longurl)
In the makeshorturl
view, we use the @api_view
decorator provided by the Django REST Framework to limit only POST requests to the view. The view receives the front-end data and creates a shorturl
from a string of predefined letters, numbers, and symbols.
The shorturl
has a length of six characters. The longurl
and shorturl
objects are then stored in the database, and a Response
is returned to the user with the long URL and the generated short URL.
The redirectUrl
view takes in the request
and shorturl
. The shorturl
parameter will be specified in the urls.py
file. This view uses a try except
statement to retrieve an object from the database where the shorturl
provided is equal to the shorturl in the database.
The user is redirected to the longurl
in the object retrieved from the database if the object is found.
To create the shorturl
, we first create a variable s
that has a set of predefined characters.
We then use the random.sample()
method to create to randomly pick six characters from the variable s
. This returns a Python list. Finally, we use the join()
method to join all the items in the list to form the shorturl
.
Working on the urls
Open the urls.py
file and modify it as shown below:
from django.urls import path
from . import views
urlpatterns = [
path('shorten/', views.makeshorturl),
path('<str:shorturl>', views.redirectUrl)
]
The above code exposes the API endpoints to be accessed by the front-end.
To run the server, run the following command:
python manage.py runserver
Setting up the frontend
Navigate into the react-drf-shortener
folder using the command prompt and run the following commands:
npx create-react-app shortener-frontend
code shortener-frontend
This creates a react app and opens it up in VS Code.
Open the App.js
file and modify it with the code provided below:
import { useState } from "react";
function App() {
const [longurl, setLongurl] = useState("");
const [shorturl, setShorturl] = useState("");
const [returnLongURL, setReturnLongURL] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
fetch("http://127.0.0.1:8000/shorten/", {
method: "POST",
body: JSON.stringify({ longurl: longurl }),
headers: { "Content-Type": "application/json" },
})
.then((res) => res.json())
.then((data) => {
setShorturl(data.shorturl);
setReturnLongURL(data.longurl);
setLongurl("");
});
};
return (
<div style={{ textAlign: "center" }}>
<input
type="text"
name="longurl"
value={longurl}
onChange={(e) => setLongurl(e.target.value)}
/>
<button
type="submit"
onClick={(e) => handleSubmit(e)}
disabled={!longurl}
>
shorten
</button>
<div>
<p>Long URL: {returnLongURL}</p>
<p
style={{ cursor: "pointer" }}
onClick={() => window.open(returnLongURL)}
>
Short URL: {shorturl}
</p>
</div>
</div>
);
}
export default App;
We import the useState()
hook from react
in the code above. We then set up three pieces of state as explained below:
longurl
- will be used to track the input provided by the user.shorturl
- will be used to hold the value of the short URL returned by the server.returnLongURL
- will be used to hold the value of the long URL provided by the server.
In the return
section, there is an input field and a button that calls the handleSubmit()
function when clicked. This function uses the fetch API
to send the longurl
to the backend. The fetch API
returns a response and sets the shorturl
and returnLongURL
values.
The long URL and the short URL are rendered on the browser. We use the window.open()
method to open the long URL on a new tab at the click of the short URL.
To run the front-end code, type in the following command in the integrated terminal and press enter:
npm start
The above command will open a local development server on 127.0.0.1:3000
Testing the shortener service
To test the service, open the browser and navigate to 127.0.0.1:3000
. Make sure that server is running.
Paste the long URL into the input field provided and click on the shorten
button. A short URL will be rendered, and on clicking it, it redirects to the same webpage as the long URL.
This means that our shortener service is working.
Proof of working application:
Proof of short URL redirecting you to the same page as the long URL:
Conclusion
We have learned how to implement a simple shortener service using React and Django. However, this project can be taken to the next level by styling the user interface and adding more features.
One of the features that may be added is counting the number of times a link has been created.
The full code for the application can be found here.
Happy coding!
Peer Review Contributions by: Srishilesh P S