<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Folafolu Osilaja</title>
    <description>The latest articles on DEV Community by Folafolu Osilaja (@folafolu).</description>
    <link>https://dev.to/folafolu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1704090%2Fd16d2c06-4970-4f66-a3db-70e939515ba1.JPG</url>
      <title>DEV Community: Folafolu Osilaja</title>
      <link>https://dev.to/folafolu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/folafolu"/>
    <language>en</language>
    <item>
      <title>Reflections on Designing a NoSQL Schema and API Endpoints for a Social Media App</title>
      <dc:creator>Folafolu Osilaja</dc:creator>
      <pubDate>Thu, 20 Feb 2025 11:20:26 +0000</pubDate>
      <link>https://dev.to/folafolu/reflections-on-designing-a-nosql-schema-and-api-endpoints-for-a-social-media-app-dd3</link>
      <guid>https://dev.to/folafolu/reflections-on-designing-a-nosql-schema-and-api-endpoints-for-a-social-media-app-dd3</guid>
      <description>&lt;p&gt;The task began with understanding the core requirements: a flexible schema to handle diverse data types like user profiles, posts, media, comments, likes, and notifications. NoSQL databases like MongoDB are ideal for such use cases because of their schema-less nature, which allows for scalability and adaptability as the app evolves.&lt;/p&gt;

&lt;p&gt;Designing the schema required balancing normalization and denormalization. For example, embedding media metadata directly within posts simplified queries but required careful handling of updates. Similarly, caching counts like likes_count and comments_count in the Posts collection improved read performance at the cost of eventual consistency.&lt;/p&gt;

&lt;p&gt;Creating the API endpoints was about ensuring usability and efficiency. Each endpoint was designed to handle specific user actions, from registering and logging in to uploading media and interacting with posts. The goal was to make the API intuitive for developers while optimizing for performance, especially with media-heavy operations.&lt;/p&gt;

&lt;p&gt;One of the most interesting aspects was accommodating media content like images, videos, and GIFs. This required thoughtful schema design to store metadata (e.g., dimensions, duration) and efficient handling of media uploads and delivery via CDNs.&lt;/p&gt;

&lt;p&gt;Overall, this assignment highlighted the importance of flexibility, scalability, and performance in modern app development. It reinforced the idea that a well-designed schema and API are the backbone of any successful social media platform, enabling seamless user experiences and future growth.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>My Experience Building a Basic REST API with Express.js and Joi Validation</title>
      <dc:creator>Folafolu Osilaja</dc:creator>
      <pubDate>Fri, 31 Jan 2025 22:15:47 +0000</pubDate>
      <link>https://dev.to/folafolu/my-experience-building-a-basic-rest-api-with-expressjs-and-joi-validation-5bpd</link>
      <guid>https://dev.to/folafolu/my-experience-building-a-basic-rest-api-with-expressjs-and-joi-validation-5bpd</guid>
      <description>&lt;p&gt;Recently, I worked on an assignment to build a simple REST API using Node.js and Express.js. The goal was to create an API for managing courses, supporting CRUD operations (Create, Read, Update, Delete). While the basic setup was straightforward, implementing Joi validation was an interesting addition that improved data integrity and error handling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Express Server
&lt;/h2&gt;

&lt;p&gt;I started by setting up an Express server and defining a list of courses as in-memory data. Implementing routes for fetching all courses, retrieving a specific course by ID, adding new courses, updating existing ones, and deleting them provided a solid foundation for API development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Challenges &amp;amp; Fixes
&lt;/h2&gt;

&lt;p&gt;Handling Missing Data in POST and PUT Requests&lt;/p&gt;

&lt;p&gt;Without validation, API users could send empty or malformed data, leading to unexpected behavior. To fix this, I integrated Joi, a popular schema validation library for JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Joi for Input Validation
&lt;/h2&gt;

&lt;p&gt;Joi allowed me to define rules, ensuring course names were at least 3 characters long and required. Implementing it in POST and PUT requests helped catch invalid inputs before they caused issues in the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Express.js makes REST API development simple, but careful handling of parameters and request-response flow is crucial.&lt;/li&gt;
&lt;li&gt;Joi is a powerful validation tool that helps enforce data integrity before processing user inputs.&lt;/li&gt;
&lt;li&gt;Meaningful error handling enhances API usability by providing clear feedback when something goes wrong.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This assignment reinforced best practices in backend development, from structuring API endpoints to improving data validation and error handling. Moving forward, I plan to explore middleware for logging, authentication, and database integration to make APIs more scalable and robust. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Step-by-Step Guide to User Authentication with Django, Djoser, and JWT</title>
      <dc:creator>Folafolu Osilaja</dc:creator>
      <pubDate>Wed, 25 Dec 2024 09:43:38 +0000</pubDate>
      <link>https://dev.to/folafolu/step-by-step-guide-to-user-authentication-with-django-djoser-and-jwt-part-i-3d8g</link>
      <guid>https://dev.to/folafolu/step-by-step-guide-to-user-authentication-with-django-djoser-and-jwt-part-i-3d8g</guid>
      <description>&lt;p&gt;User authentication and management are foundational features when starting a new project. Because these tasks are often repeated, various packages have been developed to streamline the process, allowing developers to focus on other aspects of their projects. One such package is Djoser, which integrates seamlessly with Django REST Framework (DRF) to handle authentication and user management. In this guide, I’ll walk you through building a full user authentication system using Djoser, including setting up email functionality and custom email templates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Project
&lt;/h2&gt;

&lt;p&gt;Start by creating a directory for your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir userauth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to the new directory in your preferred IDE, set up a virtual environment and activate it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python venv .venv
source .venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, install the necessary packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install django djangorestframework djoser djangorestframework_simplejwt social-auth-app-django drf-yasg

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: Some dependencies, such as social-auth-app-django, might be installed automatically with Djoser. If so, you can skip explicitly adding them&lt;/p&gt;

&lt;p&gt;Once installed, generate a requirements.txt file to track your dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip freeze &amp;gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see all the installed packages listed in the requirements.txt file, including any dependencies.&lt;/p&gt;

&lt;p&gt;Create the Django Project and get the server running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;django-admin startapp userauth . 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create the django project. We then need to create an app inside our project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py startapp accounts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your project directory should now contain the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;.venv (virtual environment)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;accounts/ (authentication app)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;userauth/ (main project folder)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;manage.py&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;requirements.txt&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuring the Project
&lt;/h2&gt;

&lt;p&gt;Add the required packages and apps to the INSTALLED_APPS section in settings.py:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

     # Third Party Apps
    'rest_framework',
    'djoser',
    'rest_framework_simplejwt',
    'drf_yasg',

    # Local Apps
    'accounts',
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update your settings.py to include configurations for Django REST Framework and SimpleJWT:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's create our custom user model since&lt;br&gt;
create managers.py file in the accounts folder&lt;br&gt;
accounts/managers.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.contrib.auth.models import BaseUserManager


class CustomUserManager(BaseUserManager):

    def create_user(self, email, username, password=None, **extra_fields) -&amp;gt; None:

        if not username:
            raise ValueError("Username is required")

        if not email:
            raise ValueError("Email is required")


        email = self.normalize_email(email)
        user = self.model(email=email, username=username, **extra_fields)
        user.set_password(password)
        user.save()
        return user


    def create_superuser(self, email, username, password, **extra_fields):
        """
        Create and save a SuperUser with the given email and password.
        """
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_superuser", True)
        extra_fields.setdefault("is_active", True)

        if extra_fields.get("is_staff") is not True:
            raise ValueError("Superuser must have is_staff=True.")

        if extra_fields.get("is_superuser") is not True:
            raise ValueError("Superuser must have is_superuser=True.")

        return self.create_user(email, username, password, **extra_fields)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;accounts/models.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.db import models
from django.contrib.auth.models import AbstractUser
from accounts.managers import CustomUserManager



class CustomUser(AbstractUser):
    username = None
    email = models.EmailField(unique=True)
    is_verified = models.BooleanField(default=False)


    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = CustomUserManager()


    def __str__(self):
        return self.email
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this line in your settings.py file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AUTH_USER_MODEL = 'accounts.CustomUser'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can go ahead to make our migrations then run the local development server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py makemigrations
python manage.py migrate
python manage.py runserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There should be no issues up to this point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Djoser URLs
&lt;/h2&gt;

&lt;p&gt;Include the URLs that Djoser provides in your project’s URL patterns, along with Swagger for API documentation:&lt;/p&gt;

&lt;p&gt;userauth/urls.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.contrib import admin
from django.urls import include, path
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi


schema_view = get_schema_view(
    openapi.Info(
        title="User Accounts API",
        default_version="v1",
        description="REST implementation of Django authentication system using Djoser",
        contact=openapi.Contact(email="contact@snippets.local"),
        license=openapi.License(name="BSD License"),
    ),
    public=True,
    permission_classes=(permissions.AllowAny,),
)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/docs', schema_view.with_ui("swagger", cache_timeout=0), name="swagger-ui"),
    path('api/', include('djoser.urls')), 
    path('api/', include('djoser.urls.jwt'))
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go to &lt;a href="http://127.0.0.1:8000/api/docs/" rel="noopener noreferrer"&gt;http://127.0.0.1:8000/api/docs/&lt;/a&gt; in your browser to view the API documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Djoser Settings
&lt;/h2&gt;

&lt;p&gt;All settings that can be configured for djoser can be found here &lt;a href="https://djoser.readthedocs.io/en/latest/settings.html" rel="noopener noreferrer"&gt;Djoser settings&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;userauth/settings.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DJOSER = {
    "LOGIN_FIELD": "email",
    "SEND_ACTIVATION_EMAIL": True,
    "ACTIVATION_URL": "accounts/activation/{uid}/{token}/",
    "SEND_CONFIRMATION_EMAIL": True,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are requiring users to receive an activation email. The activation url is the link sent to the user's email for them to click. The token and uid needs to be extracted and a post request sent with them as the body to the activation route in your project&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Email Sending
&lt;/h2&gt;

&lt;p&gt;Finally we need to configure email sending. I'll be using mailtrap for email sending. You can choose to send the email to the console or whatever email service you choose.&lt;/p&gt;

&lt;p&gt;For sending the email to your console&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using external mail service&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'sandbox.smtp.mailtrap.io'
EMAIL_PORT = '2525'
EMAIL_HOST_USER = 'email-username'
EMAIL_HOST_PASSWORD = 'email-password'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the placeholders with the correct credentials&lt;/p&gt;

&lt;p&gt;To test this out, we'll use postman to test it out.&lt;/p&gt;

&lt;p&gt;Creating a new user&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4qi8oilnv2nycvy6qgjx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4qi8oilnv2nycvy6qgjx.png" alt="Postman request" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then the activation email sent to the user&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwo9z4pum2o4xizl4jlen.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwo9z4pum2o4xizl4jlen.png" alt="Activation Email" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Customizing Email Templates
&lt;/h2&gt;

&lt;p&gt;Let's customize the email template a little&lt;br&gt;
Create a template folder in the accounts directory, then create an email folder and go ahead to create template folder in there&lt;/p&gt;

&lt;p&gt;accounts/templates/email/activation_email.py&lt;br&gt;
We customize the default email that comes with djoser&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% load i18n %}

{% block subject %}
{% blocktrans %}Account activation{% endblocktrans %}
{% endblock subject %}

{% block text_body %}
{% blocktrans %}You're receiving this email because you need to finish activation process on {{ site_name }}.{% endblocktrans %}

{% trans "Please go to the following page to activate your account:" %}
{{ protocol }}://{{ domain }}/{{ url|safe }}

{% trans "Thanks for using our site!" %}

{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endblock text_body %}

{% block html_body %}
&amp;lt;div style="font-family: Arial, sans-serif; background-color: #f9f9f9; padding: 20px;"&amp;gt;
    &amp;lt;div style="max-width: 600px; margin: 0 auto; background-color: #ffffff; border: 1px solid #ddd; border-radius: 10px; overflow: hidden;"&amp;gt;
        &amp;lt;div style="background-color: #4CAF50; color: white; padding: 20px; text-align: center;"&amp;gt;
            &amp;lt;h1 style="margin: 0;"&amp;gt;{{ site_name }}&amp;lt;/h1&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div style="padding: 20px;"&amp;gt;
            &amp;lt;p style="font-size: 16px; color: #333;"&amp;gt;
                {% blocktrans %}You're receiving this email because you need to finish the activation process on {{ site_name }}.{% endblocktrans %}
            &amp;lt;/p&amp;gt;
            &amp;lt;p style="font-size: 16px; color: #333;"&amp;gt;
                {% trans "Please go to the following page to activate your account:" %}
            &amp;lt;/p&amp;gt;
            &amp;lt;p style="text-align: center; margin: 20px 0;"&amp;gt;
                &amp;lt;a href="{{ protocol }}://{{ domain }}/{{ url|safe }}" style="background-color: #4CAF50; color: white; text-decoration: none; padding: 10px 20px; border-radius: 5px; font-size: 16px; display: inline-block;"&amp;gt;
                    {% trans "Activate Account" %}
                &amp;lt;/a&amp;gt;
            &amp;lt;/p&amp;gt;
            &amp;lt;p style="font-size: 16px; color: #333;"&amp;gt;
                {% trans "Thanks for using our site!" %}
            &amp;lt;/p&amp;gt;
            &amp;lt;p style="font-size: 16px; color: #333; font-weight: bold;"&amp;gt;
                {% blocktrans %}The {{ site_name }} team{% endblocktrans %}
            &amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div style="background-color: #f1f1f1; color: #999; text-align: center; padding: 10px; font-size: 12px;"&amp;gt;
            {% trans "If you did not request this email, you can safely ignore it." %}
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
{% endblock html_body %}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create email.py file in accounts directory&lt;br&gt;
accounts/email.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from djoser import email


class ActivationEmail(email.ActivationEmail):
    template_name = 'email/activation_email.html'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To customize the  site name in the template, add this line to the djoser setting&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DJOSER = {
    "LOGIN_FIELD": "email",
    "EMAIL_FRONTEND_SITE_NAME": 'My App',  # Add this line
    "SEND_ACTIVATION_EMAIL": True,
    "ACTIVATION_URL": "accounts/activation/{uid}/{token}/",
    "SEND_CONFIRMATION_EMAIL": True,
    "EMAIL": {
        "activation": "accounts.email.ActivationEmail",
    },
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The email template looks like this now &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u4n8qpuuizieh6khlnw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u4n8qpuuizieh6khlnw.png" alt="Customized email" width="800" height="615"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Extending Activation View
&lt;/h2&gt;

&lt;p&gt;For the last part of this article, let work on the email verification.&lt;br&gt;
We start by customizing the activation view in accounts/views.py:&lt;/p&gt;

&lt;p&gt;accounts/views.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from rest_framework.response import Response
from rest_framework import status
from djoser.views import UserViewSet


# Create your views here.


class ActivationView(UserViewSet):
    def activation(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.user
        user.is_verified = True
        user.save()
        super().activation(request, *args, **kwargs)
        return Response(
            {"message": "Account activated successfully and verified!"},
            status=status.HTTP_200_OK,
        )

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are extending the activation view on djoser to customize it and set the is_verified field on our user model to true&lt;/p&gt;

&lt;p&gt;accounts/urls.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.urls import path
from accounts.views import ActivationView


urlpatterns = [
    path("accounts/activation/", ActivationView.as_view({'post': 'activation'}), name="email-activation")
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Urls file in the project level&lt;br&gt;
userauth/urls.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/docs/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
    path('api/', include('djoser.urls')), 
    path('api/', include('djoser.urls.jwt')),
    path('api/', include('accounts.urls'))   # Add this line
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test this out create a new test user and click the activation url sent to the email.&lt;br&gt;
You get to this page, because the url does not exist in our project&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshljcbcaz5lgqg8exj6j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshljcbcaz5lgqg8exj6j.png" alt="Verify user" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;from the url extract the uid and token and make a post request to the activation route you defined in your accounts/urls.py file&lt;/p&gt;

&lt;p&gt;from the screenshot, my route is ;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://127.0.0.1:8000/accounts/verify/MTY/cil456-aaf8331efb885f0b4412f35ce544648c/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The uid is MTY&lt;br&gt;
The token  is cil456-aaf8331efb885f0b4412f35ce544648c&lt;/p&gt;

&lt;p&gt;Using the parameters to make a post request to the activate endpoint&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F50qh6ic17y9837mzcsnw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F50qh6ic17y9837mzcsnw.png" alt="Verify Post request" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This concludes the tutorial for setting up user authentication with Djoser. You now have a functional authentication system with email activation and customizable templates.&lt;/p&gt;

&lt;p&gt;If you have any questions or feedback, feel free to leave a comment. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>django</category>
      <category>python</category>
      <category>backenddevelopment</category>
    </item>
    <item>
      <title>My Dev Journey: Tackling Real-Time Challenge with Django and the HNG Internship</title>
      <dc:creator>Folafolu Osilaja</dc:creator>
      <pubDate>Sat, 29 Jun 2024 17:28:40 +0000</pubDate>
      <link>https://dev.to/folafolu/my-dev-journey-tackling-real-time-challenge-with-django-and-the-hng-internship-483j</link>
      <guid>https://dev.to/folafolu/my-dev-journey-tackling-real-time-challenge-with-django-and-the-hng-internship-483j</guid>
      <description>&lt;p&gt;I recently tackled a problem to implement real time communication feature in my web application. I'll be sharing how I did it in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Real Time Communication Challenge
&lt;/h2&gt;

&lt;p&gt;Recently, I had to implement WebSockets in one of my personal projects, something I had never done before. This led me to Django Channels, a package for handling WebSockets in Django.&lt;br&gt;
It was a good learning experience for me as I had to learn a bit of Javascript too. So after a bit of tutorials and research, I was ready to solve my problem.&lt;/p&gt;

&lt;p&gt;Django-channels works by creating a consumer and routes in the backend, while Javascript is used in the frontend to open a websocket connection to the specified routes and keeps the connection open so data can be exchanged in real time between the backend and the frontend.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setting up Django channels
&lt;/h3&gt;

&lt;p&gt;Installing django-channels&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  pip install channels

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Updating settings.py file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
    ...
    'channels',
]

ASGI_APPLICATION = 'educa.asgi.application'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating the web consumer
&lt;/h3&gt;

&lt;p&gt;A consumer handles the Websocket connections&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import json
from channels.generic.websocket import AsyncWebsocketConsumer
from django.utils import timezone

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.user = self.scope['user']
        self.id = self.scope['url_route']['kwargs']['course_id']
        self.room_group_name = f'chat_{self.id}'
        # join room group
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )
        # accept connection
        await self.accept()

      async def disconnect(self, close_code):
        # leave room group
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    # receive message from WebSocket
    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']
        now = timezone.now()
        # send message to room group
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message,
                'user': self.user.username,
                'datetime': now.isoformat(),
            }
        )

    # receive message from room group
    async def chat_message(self, event):
        # send message to WebSocket
        await self.send(text_data=json.dumps(event))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up the routes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.urls import re_path
from . import consumers

websocket_urlpatterns = [
    re_path(r'ws/chat/room/(?P&amp;lt;course_id&amp;gt;\d+)/$',
            consumers.ChatConsumer.as_asgi()),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuring asgi.py file
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import os

from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
from channels.auth import AuthMiddlewareStack
import chat.routing

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'educa.settings')

django_asgi_app = get_asgi_application()

application = ProtocolTypeRouter({
    'http': django_asgi_app,
    'websocket': AuthMiddlewareStack(
        URLRouter(chat.routing.websocket_urlpatterns)
       ),
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Frontend Websocket connection
&lt;/h3&gt;

&lt;p&gt;Finally I wrote the javascript code to open the Websocket connection&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const courseId = JSON.parse(
    document.getElementById('course-id').textContent
  );
  const requestUser = JSON.parse(
    document.getElementById('request-user').textContent
  );
  const url = 'wss://' + window.location.host +
              '/ws/chat/room/' + courseId + '/';
  const chatSocket = new WebSocket(url);
a
  chatSocket.onmessage = function(event) {
    const data = JSON.parse(event.data);
    const chat = document.getElementById('chat');

    const dateOptions = {hour: 'numeric', minute: 'numeric', hour12: true};
    const datetime = new Date(data.datetime).toLocaleString('en', dateOptions);
    const isMe = data.user === requestUser;
    const source = isMe ? 'me' : 'other';
    const name = isMe ? 'Me' : data.user;

    chat.innerHTML += '&amp;lt;div class="message ' + source + '"&amp;gt;' +
                      '&amp;lt;strong&amp;gt;' + name + '&amp;lt;/strong&amp;gt; ' +
                      '&amp;lt;span class="date"&amp;gt;' + datetime + '&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;' +
                      data.message + '&amp;lt;/div&amp;gt;';
  };

  chatSocket.onclose = function(event) {
    console.error('Chat socket closed unexpectedly');
  };

  const input = document.getElementById('chat-message-input');
  const submitButton = document.getElementById('chat-message-submit');

  submitButton.addEventListener('click', function(event) {
    const message = input.value;
    if(message) {
      // send message in JSON format
      chatSocket.send(JSON.stringify({'message': message}));
      // clear input
      input.value = '';
      input.focus();
    }
  });

  input.addEventListener('keypress', function(event) {
    if (event.key === 'Enter') {
      // cancel the default action, if needed
      event.preventDefault();
      // trigger click event on button
      submitButton.click();
    }
  });

  input.focus();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This project was a significant learning experience. Not only did I learn Django Channels, but I also got hands-on with JavaScript. &lt;/p&gt;

&lt;p&gt;This is my first attempt at writing an article. I have always wanted to write articles, especially on technical topics relating to programming, but I haven't being able to bring myself to start.&lt;br&gt;
Funny enough, a program I joined has actually pushed me to write this article and publish it. That program is the HNG Internship&lt;/p&gt;

&lt;h2&gt;
  
  
  What is HNG Internship
&lt;/h2&gt;

&lt;p&gt;This internship is a fast paced boot camp for advanced learners to get in shape for job offers. It provides you with the opportunity to gain real-world experience by working on actual projects for eight weeks and also network with like minded individuals.&lt;br&gt;
You can read more about HNG Internship &lt;a href="https://hng.tech/internship" rel="noopener noreferrer"&gt;here&lt;/a&gt;. You can also explore the &lt;a href="https://hng.tech/premium" rel="noopener noreferrer"&gt;HNG premium network&lt;/a&gt; which gives you the opportunity to get access to exclusive opportunities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I joined HNG Internship
&lt;/h2&gt;

&lt;p&gt;I joined the program so I could gain more confidence in applying for jobs seeing that throughout the 8 weeks, I will be working on real project, which is a much needed experience for me right now. I will be pushing myself to limits and boundaries I have never crossed in my programming journey during this program. I have been pushed to write this article so I can be promoted the next stage.&lt;/p&gt;

&lt;p&gt;Thank you for reading. I hope to share more about my dev journey and experience during HNG Internship with you.&lt;/p&gt;

</description>
      <category>hng</category>
      <category>django</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
