DEV Community

Cover image for A Definitive Guideline for Creating APIs with Django and Neo4j database, Part-2
Afroza Nowshin
Afroza Nowshin

Posted on • Edited on

A Definitive Guideline for Creating APIs with Django and Neo4j database, Part-2

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')),
Enter fullscreen mode Exit fullscreen mode

Create a superuser for your Django project by this command :

python manage.py createsuperuser
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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'),


]

Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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'),
Enter fullscreen mode Exit fullscreen mode

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):

sign up

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
}
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

Which yields :

cypher

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
Enter fullscreen mode Exit fullscreen mode
  • Serialize each fields of the model
class Neo4jUserSerializer(serializers.Serializer):
    username = serializers.CharField()
    email = serializers.CharField()
    phone = serializers.CharField()
    password = serializers.CharField()
Enter fullscreen mode Exit fullscreen mode
  • 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
Enter fullscreen mode Exit fullscreen mode
  • 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')
Enter fullscreen mode Exit fullscreen mode
  • 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
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

You will now be able to see the data as the way they were saved in the model:


{
    username: 'user 1',
    phone: '01666666666'
}

Enter fullscreen mode Exit fullscreen mode

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.

Top comments (1)

Collapse
 
sanlobach789 profile image
Aleksandr Lobach

Thanks for this guideline! <3