A Definitive Guideline for Creating APIs with Django and Neo4j database, Part-2
Afroza Nowshin
Posted on August 26, 2023
In today's post, we will breakdown the middle part of the architecture (referred to this post). In a word, we need to create views for each of the API URLs. First, all you have to do is create a file named "urls.py" inside your app folder. And in your project's urls.py file, add the following line under the url for the admin page:
path('', include('yourappname.urls')),
Create a superuser for your Django project by this command :
python manage.py createsuperuser
And provide your username and password for the admin.
1. Sign Up API view and URL
Your first job is to import all the dependencies and the model in your views.py file.
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import NeoUser
Response returns the API response in a JSON format and status is requires for required HTTP codes while querying.
Now you need to capture the fields of your API request and check for empty field. We are using Django's class-based views (CBV). And as we are posting data to our database, the request type will be POST, hence the function.
class SignUp(APIView):
def post(self, request):
username = request.data.get('username')
email = request.data.get('email')
password = request.data.get('password')
if not username or not email or not password:
return Response({"error": "Please provide username,
email, and password."}, status=status.HTTP_400_BAD_REQUEST)
The final step is to save the data as nodes and return the response as an HTTP code:
try:
user = NeoUser.nodes.get(username=username)
return Response({"error": "Username already exists."}, status=status.HTTP_409_CONFLICT)
except User.DoesNotExist:
user = NeoUser(username=username, email=email, password=hashed_password)
user.save()
return Response({"message": "User created successfully."}, status=status.HTTP_201_CREATED)
Few things to keep in mind:
- For creating an object or node, return HTTP code 201
- For a successful query, return HTTP code 200
- For bad request or sending a request without following the rules, return HTTP code 400
- For unauthorized request, return HTTP code 401
- And lastly, return HTTP code 404 when not found
Now go to your app's urls.py file and add the url for your created view:
from django.urls import path
from . import views
urlpatterns = [
path('api/signup', views.UserSignupView.as_view(), name='user-signup'),
]
2. Users API view and URL
We will retrieve data from the database, so we need to implement a GET request. The rest of the steps are like the previous section.
views.py
class UserListView(APIView):
def get(self, request):
users = NeoUser.nodes.all()
if not users:
return Response({"message": "No users found"}, status=status.HTTP_404_NOT_FOUND)
return Response(users, status=status.HTTP_200_OK)
Now inside yourapp/urls.py, add the following line right after the sign-up url:
...
path('api/userlist/', views.UserListView.as_view(), name='user-list'),
You have made 2 APIs now. Hit them in Postman like the following way while running your Django server(my field was named fullname in the model, change it to the field you put in the model):
3. Creating Serializers
If you hit your created User list api in Curl or Postman, You will see that the response json is showing null values for each field of a user:
{
"username": null,
"phone" : null
}
This is weird, because in your cypher-shell or Neo4j Desktop app, if you run the following command, there are nodes showing there:
MATCH (n:NeoUser) RETURN n LIMIT 25
Which yields :
While we are making our queries in the database, we need to "serialize" it, which converts the saved bits of the database into respective data types of each data. Additionally, there are verification steps for our sign up API such as, not signing up with the same username or phone number. We can either do this in our views.py or inside our serializer. I will show this process inside our serializer. Create a serializers.py inside your app's folder. This is the steps for making a serializer for your user data:
- Import Rest Framework's serializer class and models
from rest_framework import serializers
from .models import NeoUser
- Serialize each fields of the model
class Neo4jUserSerializer(serializers.Serializer):
username = serializers.CharField()
email = serializers.CharField()
phone = serializers.CharField()
password = serializers.CharField()
- Validate and check for duplicates
def validate(self, data):
id = data.get('uid')
username = data.get('username')
email = data.get('email')
phone = data.get('phone')
if NeoUser.nodes.filter(username=username):
raise serializers.ValidationError("Username already
exists")
...
return data
- Create a queryset with the validated data
def create(self, validated_data):
username = validated_data.get('fullname')
email = validated_data.get('email')
password = validated_data.get('password')
phone = validated_data.get('phone')
- Create a node with the queryset and save the node
neo_user = NeoUser(uid=id,fullname=username, email=email,password=password,emp_id=emp_id,phone=phone)
neo_user.save()
# don't forget to return the queryset
return validated_data
The entire seializer code is here:
from rest_framework import serializers
from .models import NeoUser
class Neo4jUserSerializer(serializers.Serializer):
username = serializers.CharField()
email = serializers.CharField()
phone = serializers.CharField()
password = serializers.CharField()
def validate(self, data):
id = data.get('uid')
username = data.get('username')
email = data.get('email')
phone = data.get('phone')
if NeoUser.nodes.filter(username=username):
raise serializers.ValidationError("Username already
exists")
# other field's duplicate checking
return data
def create(self, validated_data):
username = validated_data.get('fullname')
email = validated_data.get('email')
password = validated_data.get('password')
phone = validated_data.get('phone')
neo_user = NeoUser(uid=id,fullname=username, email=email,password=password,emp_id=emp_id,phone=phone)
neo_user.save()
return validated_data
4. Adding serializer in the views
We are almost done. All you have to do is add the serializers in the views that you have created before. In sign up API, you have to make a validity check before saving.
class UserSignupView(APIView):
def post(self, request):
if request.method == 'POST':
serializer = Neo4jUserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({"message": "User registered successfully", "status": 200}, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
For the user list API, you pass your node objects in the serializer and the serializer will return the serialized nodes for you:
class UserListView(APIView):
def get(self, request):
users = NeoUser.nodes.all()
if not users:
return Response({"message": "No users found"}, status=status.HTTP_404_NOT_FOUND)
serializer = Neo4jUserSerializer(users, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
You will now be able to see the data as the way they were saved in the model:
{
username: 'user 1',
phone: '01666666666'
}
Following these steps, you can make your own login API. If you are facing any issue, let me know in the comments below. In the next post, we will learn an important topic about user authentication in the system - JWT based Authentication. Take care and bye for now.
Posted on August 26, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
August 26, 2023
August 24, 2023