<?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>Forem: Mateo Ramirez Rubio</title>
    <description>The latest articles on Forem by Mateo Ramirez Rubio (@mateoramirezr).</description>
    <link>https://forem.com/mateoramirezr</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%2F1743449%2F4f728917-8640-49d2-954f-8bf7f5026fa1.png</url>
      <title>Forem: Mateo Ramirez Rubio</title>
      <link>https://forem.com/mateoramirezr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mateoramirezr"/>
    <language>en</language>
    <item>
      <title>Configuring AWS VPC, Load Balancers, and DNS for WordPress and Moodle Integration</title>
      <dc:creator>Mateo Ramirez Rubio</dc:creator>
      <pubDate>Sat, 07 Sep 2024 02:15:02 +0000</pubDate>
      <link>https://forem.com/mateoramirezr/configuring-aws-vpc-load-balancers-and-dns-for-wordpress-and-moodle-integration-47bd</link>
      <guid>https://forem.com/mateoramirezr/configuring-aws-vpc-load-balancers-and-dns-for-wordpress-and-moodle-integration-47bd</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Implementing High-Availability VPC Architectures, DNS Routing, and Load Balancing for WordPress and Moodle in AWS&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Table of Contents&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Introduction.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;System Architecture.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Implementation and Deployment.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* Configuration of the **VPC** and Subnets.

* Configuration of the **DNS Server.**

* Configuration of the **Load Balancer (HAProxy).**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Installation and Configuration of WordPress.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Installation and Configuration of Moodle.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Verification and Results.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Issues Encountered During Development, Troubleshooting, and/or Recommendations.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conclusions.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;References.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;List of Figures&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AWS Resource Map.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Screenshot of EC2 Instances in AWS.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;BIND Configuration File&lt;/strong&gt; &lt;code&gt;named.conf.local&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;BIND Configuration File&lt;/strong&gt; &lt;code&gt;db.learxyz.online&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;BIND Configuration File&lt;/strong&gt; &lt;code&gt;db.10&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HAProxy Configuration File&lt;/strong&gt; &lt;code&gt;haproxy.cfg&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HAProxy Statistics Page.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;WordPress Main Page.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Moodle Learning Portal.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AWS Security Group Configuration.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Route 53 Configuration.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DNS Propagation Verification on WhatsMyDNS.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The project involves the deployment of a &lt;strong&gt;cloud services environment&lt;/strong&gt; for &lt;strong&gt;XYZ S.A. Manufacturas (Fictitious not real company)&lt;/strong&gt;. The goal is to create a scalable and highly available infrastructure using &lt;strong&gt;AWS&lt;/strong&gt;, which includes a &lt;strong&gt;CMS&lt;/strong&gt; (WordPress), an &lt;strong&gt;LMS&lt;/strong&gt; (Moodle), and a load balancer (&lt;strong&gt;HAProxy&lt;/strong&gt;). The setup includes creating a &lt;strong&gt;VPC&lt;/strong&gt; with public and private subnets, installing services on &lt;strong&gt;EC2 instances&lt;/strong&gt;, and configuring a domain in &lt;strong&gt;Route 53&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  System Architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  AWS Resource Map
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Figure 1: AWS Resource Map&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgkiogaopnaqy175gw41o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgkiogaopnaqy175gw41o.png" alt="AWS Resource Map" width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The resource map shows the &lt;strong&gt;VPC&lt;/strong&gt; structure implemented for &lt;strong&gt;XYZ S.A. Manufacturas&lt;/strong&gt;. It includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;VPC (Virtual Private Cloud)&lt;/strong&gt;: &lt;code&gt;XYZSA-vpc-01&lt;/code&gt;, which houses all network resources.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Subnets&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Public-subnet-XYZSA-01&lt;/code&gt;: Public subnet containing the public instance.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Private-subnet-XYZSA-01&lt;/code&gt;: Private subnet containing application and database instances.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Route Tables&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Public-Route-Table-XYZSA-VPC&lt;/code&gt;: Manages traffic for the public subnet.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Private-Route-Table-XYZSA-VPC&lt;/code&gt;: Manages traffic for the private subnet.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Network Connections&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Internet Gateway&lt;/strong&gt; (&lt;code&gt;ig-XYZSA-vpc&lt;/code&gt;): Enables Internet connectivity for the &lt;strong&gt;VPC&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NAT Gateway&lt;/strong&gt; (&lt;code&gt;Nat-gateway-XYZSA-VPC&lt;/code&gt;): Enables instances in the private subnet to securely access the Internet.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Implementation and Deployment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  VPC and Subnet Configuration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Figure 2: Screenshot of EC2 Instances in AWS&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftay2843k3c5secq5u5bp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftay2843k3c5secq5u5bp.png" alt="Screenshot of EC2 Instances in AWS" width="800" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This screenshot shows the &lt;strong&gt;EC2 instances&lt;/strong&gt; deployed in AWS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;private-instance-CMS-01-XYZSA&lt;/strong&gt; and &lt;strong&gt;private-instance-CMS-02-XYZSA&lt;/strong&gt;: These instances host the &lt;strong&gt;WordPress CMS&lt;/strong&gt;. Having two instances allows for &lt;strong&gt;high availability&lt;/strong&gt; and &lt;strong&gt;load balancing&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;private-instance-DB-01-XYZSA&lt;/strong&gt;: This instance hosts the &lt;strong&gt;MariaDB database&lt;/strong&gt;, accessible only from the application instances.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;private-instance-LMS-01-XYZSA&lt;/strong&gt;: This instance runs the &lt;strong&gt;Moodle LMS&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;public-instance-01-XYZSA&lt;/strong&gt;: This public instance acts as a &lt;strong&gt;load balancer&lt;/strong&gt; and &lt;strong&gt;DNS server&lt;/strong&gt;, directing traffic to the appropriate instances in the private subnet.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DNS Server Configuration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Figure 3: BIND Configuration File&lt;/em&gt;&lt;/strong&gt; &lt;code&gt;named.conf.local&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumatkqybn0ufmfdr0r0i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumatkqybn0ufmfdr0r0i.png" alt="BIND Configuration File named.conf.local" width="713" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This file configures the &lt;strong&gt;BIND DNS server&lt;/strong&gt; to resolve domain names to IP addresses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;zone "learxyz.online"&lt;/strong&gt;: Defines the primary zone for the domain &lt;code&gt;learxyz.online&lt;/code&gt;, indicating that DNS records for this domain are in &lt;code&gt;db.learxyz.online&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;zone "1.0.10.in-addr.arpa"&lt;/strong&gt;: Defines the zone for &lt;strong&gt;reverse IP resolution&lt;/strong&gt; in the 10.0.1.0 subnet, with records in &lt;code&gt;db.10&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Figure 4: BIND Configuration File&lt;/em&gt;&lt;/strong&gt; &lt;code&gt;db.learxyz.online&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftepmdu0w9o7ydk6h3w79.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftepmdu0w9o7ydk6h3w79.png" alt="BIND Configuration File db.learxyz.online" width="765" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This file contains the specific DNS records for &lt;code&gt;learxyz.online&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SOA Record&lt;/strong&gt;: Defines the origin server and zone update parameters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NS Records&lt;/strong&gt;: &lt;code&gt;ns1.learxyz.online&lt;/code&gt; and &lt;code&gt;ns2.learxyz.online&lt;/code&gt; are the authoritative name servers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A Records&lt;/strong&gt;: &lt;code&gt;ns1&lt;/code&gt; and &lt;code&gt;ns2&lt;/code&gt; point to &lt;code&gt;100.27.144.145&lt;/code&gt; (elastic IP of the public instance). The &lt;code&gt;@&lt;/code&gt; (root domain) also points to &lt;code&gt;100.27.144.145&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CNAME Record&lt;/strong&gt;: &lt;code&gt;www.learxyz.online&lt;/code&gt; is an alias pointing to &lt;code&gt;@&lt;/code&gt;, resolving to &lt;code&gt;100.27.144.145&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A Record&lt;/strong&gt;: &lt;code&gt;lms.learxyz.online&lt;/code&gt; points to &lt;code&gt;100.27.144.145&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These records ensure that all DNS requests for &lt;strong&gt;learxyz.online&lt;/strong&gt; and its subdomains are directed to the &lt;strong&gt;elastic IP&lt;/strong&gt; of the public instance, where &lt;strong&gt;HAProxy&lt;/strong&gt; will load balance the traffic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Figure 5: BIND Configuration File&lt;/em&gt;&lt;/strong&gt; &lt;code&gt;db.10&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbuwzof0emt388ou863x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbuwzof0emt388ou863x.png" alt="BIND Configuration File db.10" width="784" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This file contains the &lt;strong&gt;reverse resolution&lt;/strong&gt; records:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PTR Records&lt;/strong&gt;: Maps IP addresses to corresponding domain names. &lt;code&gt;10.0.1.10&lt;/code&gt; resolves to &lt;code&gt;www.learxyz.online&lt;/code&gt; and &lt;code&gt;10.0.1.12&lt;/code&gt; to &lt;code&gt;lms.learxyz.online&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These records allow for &lt;strong&gt;reverse DNS resolution&lt;/strong&gt;, useful for diagnostics and certain applications requiring domain name verification from IPs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Load Balancer Configuration (HAProxy)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Figure 6: HAProxy Configuration File&lt;/em&gt;&lt;/strong&gt; &lt;code&gt;haproxy.cfg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpb89dv4oa2ttc7jv3fla.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpb89dv4oa2ttc7jv3fla.png" alt="HAProxy Configuration File haproxy.cfg" width="790" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This file configures &lt;strong&gt;HAProxy&lt;/strong&gt;, the &lt;strong&gt;load balancer&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Listen stats&lt;/strong&gt;: Enables the statistics interface on port &lt;code&gt;8080&lt;/code&gt;, accessible with basic authentication.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Frontend http_front&lt;/strong&gt;: Defines a frontend listening on port &lt;code&gt;80&lt;/code&gt;. Uses &lt;strong&gt;ACLs&lt;/strong&gt; to redirect traffic based on the host name:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;learxyz.online&lt;/code&gt; and &lt;code&gt;www.learxyz.online&lt;/code&gt; are directed to the backend &lt;code&gt;wordpress_servers&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lms.learxyz.online&lt;/code&gt; is directed to the backend &lt;code&gt;moodle_servers&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Backend wordpress_servers&lt;/strong&gt;: Balances traffic between two &lt;strong&gt;WordPress instances&lt;/strong&gt; (&lt;code&gt;10.0.1.119&lt;/code&gt; and &lt;code&gt;10.0.1.129&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Backend moodle_servers&lt;/strong&gt;: Balances traffic to the &lt;strong&gt;Moodle instance&lt;/strong&gt; (&lt;code&gt;10.0.1.174&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;HAProxy&lt;/strong&gt; distributes incoming requests to the appropriate instances, ensuring &lt;strong&gt;high availability&lt;/strong&gt; and &lt;strong&gt;redundancy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Figure 7: HAProxy Statistics Page&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ee5inh1jy80ya9982rk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ee5inh1jy80ya9982rk.png" alt="HAProxy Statistics Page" width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This page provides real-time statistics on &lt;strong&gt;HAProxy's performance&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Connection Status&lt;/strong&gt;: Shows the number of active and queued connections.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Processed Traffic&lt;/strong&gt;: Incoming and outgoing bytes, denied requests, and errors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Backend Instance Status&lt;/strong&gt;: Indicates whether instances are active and available for load balancing.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  WordPress Installation and Configuration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Figure 8: WordPress Homepage&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flgfqalubm0vupuzfnr4n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flgfqalubm0vupuzfnr4n.png" alt="WordPress Homepage1" width="755" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpx6igbssx4yc0iy0pop7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpx6igbssx4yc0iy0pop7.png" alt="WordPress Homepage2" width="780" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These images show the homepage of the &lt;strong&gt;WordPress site&lt;/strong&gt; at &lt;code&gt;www.learxyz.online&lt;/code&gt;. The page changes language when reloaded in the browser to demonstrate &lt;strong&gt;load balancing&lt;/strong&gt;, distributing requests between the two &lt;strong&gt;WordPress instances&lt;/strong&gt;. This ensures the site remains available even if one instance fails.&lt;/p&gt;

&lt;h3&gt;
  
  
  Moodle Installation and Configuration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Figure 9: Moodle Learning Portal&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgsrggp4unb0kigfky8o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgsrggp4unb0kigfky8o.png" alt="Moodle Learning Portal" width="800" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This image shows the &lt;strong&gt;Moodle learning portal&lt;/strong&gt; at &lt;code&gt;lms.learxyz.online&lt;/code&gt;. The course "Introduction to XYZ Manufacturing" is available, designed to train employees on the company's manufacturing processes. &lt;strong&gt;Moodle&lt;/strong&gt; is configured to provide a robust and scalable platform for &lt;strong&gt;online education and training&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verification and Results
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Figure 10: AWS Security Group Configuration&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgmzwe2uj042uofvhyn8d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgmzwe2uj042uofvhyn8d.png" alt="AWS Security Group Configuration" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security Group&lt;/strong&gt; rules control access to &lt;strong&gt;EC2 instances&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ICMP&lt;/strong&gt;: Allows all &lt;strong&gt;ICMP packets&lt;/strong&gt; for diagnostics (ping).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SSH (22)&lt;/strong&gt;: Allows &lt;strong&gt;SSH access&lt;/strong&gt; for remote administration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MySQL/Aurora (3306)&lt;/strong&gt;: Allows &lt;strong&gt;MySQL traffic&lt;/strong&gt; from any IP, enabling connection to the database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DNS (UDP 53)&lt;/strong&gt; and &lt;strong&gt;DNS (TCP 53)&lt;/strong&gt;: Allow DNS traffic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Custom TCP (8080)&lt;/strong&gt;: Allows access to the &lt;strong&gt;HAProxy statistics page&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HTTP (80)&lt;/strong&gt; and &lt;strong&gt;HTTPS (443)&lt;/strong&gt;: Allow HTTP and HTTPS traffic for web access.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These rules ensure that instances are accessible only through the necessary ports, improving security.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Figure 11: Route 53 Configuration&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwdic90ootdbx376wcq4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwdic90ootdbx376wcq4.png" alt="Route 53 Configuration" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Route 53&lt;/strong&gt; manages traffic routing for &lt;code&gt;learxyz.online&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A Record&lt;/strong&gt;: &lt;code&gt;learxyz.online&lt;/code&gt; points to &lt;strong&gt;elastic IP&lt;/strong&gt; &lt;code&gt;100.27.144.145&lt;/code&gt;, directing all traffic to the load balancer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NS Records&lt;/strong&gt;: Defines the &lt;strong&gt;authoritative name servers&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SOA Record&lt;/strong&gt;: Contains origin server information and zone parameters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A Record&lt;/strong&gt;: &lt;code&gt;lms.learxyz.online&lt;/code&gt; points to &lt;code&gt;100.27.144.145&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CNAME Record&lt;/strong&gt;: &lt;code&gt;www.learxyz.online&lt;/code&gt; is an alias pointing to &lt;code&gt;learxyz.online&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These records ensure that requests for &lt;code&gt;learxyz.online&lt;/code&gt; and its subdomains are properly directed to the &lt;strong&gt;public instance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5e93pjccqfm8vbhwinef.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5e93pjccqfm8vbhwinef.png" alt="Route 53 Configuration2" width="513" height="756"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Figure 12: DNS Propagation Verification in WhatsMyDNS&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hh7g8i71n5czg8aq7tu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hh7g8i71n5czg8aq7tu.png" alt="DNS Propagation Verification in WhatsMyDNS1" width="589" height="780"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flowm83iil8lyyrktzl7c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flowm83iil8lyyrktzl7c.png" alt="DNS Propagation Verification in WhatsMyDNS2" width="800" height="51"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This image shows &lt;strong&gt;DNS record propagation&lt;/strong&gt; using &lt;strong&gt;WhatsMyDNS&lt;/strong&gt;. Successful global propagation ensures that &lt;code&gt;learxyz.online&lt;/code&gt; resolves correctly to &lt;code&gt;100.27.144.145&lt;/code&gt; from multiple locations worldwide, guaranteeing &lt;strong&gt;accessibility&lt;/strong&gt; and &lt;strong&gt;redundancy&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Issues Encountered, Troubleshooting, and Recommendations
&lt;/h2&gt;

&lt;p&gt;Several issues were encountered during project development that required attention and resolution:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;DNS Server Configuration:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Issue:** DNS records did not propagate correctly initially.

* **Solution:** The BIND records were reviewed and corrected, ensuring the name servers pointed to the correct elastic IP. WhatsMyDNS was used to confirm global propagation of the records.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;HAProxy Load Balancer Configuration:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Issue:** HTTP traffic was not evenly distributed between the WordPress instances.

* **Solution:** ACLs and backend settings in haproxy.cfg were adjusted to ensure all requests were properly load balanced.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;WordPress and Moodle Installation:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Issue:** WordPress instances displayed the default Apache page instead of WordPress content.

* **Solution:** WordPress files were correctly moved to the web server's root directory, and the proper permissions were set.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Security Group Configuration:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Issue:** Access to necessary service ports was restricted.

* **Solution:** Security Group rules were updated to allow traffic on specific ports (80, 443, 22, 3306, 53, 8080).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Moodle Configuration:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Issue:** Missing required PHP extensions during Moodle installation.

* **Solution:** Required PHP extensions (xml, intl, zip, etc.) were installed and enabled, and PHP configurations (max\_input\_vars, memory\_limit) were adjusted to meet Moodle’s requirements.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;The project demonstrated XYZ S.A. Manufacturas’ ability to implement a scalable and highly available cloud infrastructure. AWS and HAProxy provided the necessary flexibility and redundancy to support the company’s critical applications. The following points highlight the project’s conclusions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability:&lt;/strong&gt; The infrastructure can easily scale to handle increased traffic and workload.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;High Availability:&lt;/strong&gt; Redundancy and load balancing ensure that services remain available even if an instance fails.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security:&lt;/strong&gt; Proper configuration of Security Groups and access policies ensures resources are accessible only by authorized users.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Future Work&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Future recommendations for XYZ S.A. Manufacturas include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automation:&lt;/strong&gt; Implement AWS Lambda functions to automate system monitoring and scaling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitoring:&lt;/strong&gt; Use AWS CloudWatch for real-time monitoring of infrastructure performance and resource utilization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Disaster Recovery:&lt;/strong&gt; Set up automatic backups and a disaster recovery plan to ensure business continuity in case of failures.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;"Amazon Web Services (AWS) Documentation," AWS, [Online]. Available: &lt;a href="https://docs.aws.amazon.com/" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"HAProxy Documentation," HAProxy Technologies, [Online]. Available: &lt;a href="https://www.haproxy.org/" rel="noopener noreferrer"&gt;https://www.haproxy.org/&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"Moodle Documentation," Moodle, [Online]. Available: &lt;a href="https://docs.moodle.org/" rel="noopener noreferrer"&gt;https://docs.moodle.org/&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"WordPress Documentation," WordPress, [Online]. Available: &lt;a href="https://wordpress.org/documentation/" rel="noopener noreferrer"&gt;https://wordpress.org/documentation/&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Quick Introduction to Parallel Computing in Go: A Practical Approach with Goroutines, WaitGroups, Mutexes and Atomic Operations</title>
      <dc:creator>Mateo Ramirez Rubio</dc:creator>
      <pubDate>Mon, 19 Aug 2024 01:44:56 +0000</pubDate>
      <link>https://forem.com/mateoramirezr/quick-introduction-to-parallel-computing-in-go-a-practical-approach-with-goroutines-waitgroups-mutexes-and-atomic-operations-4agk</link>
      <guid>https://forem.com/mateoramirezr/quick-introduction-to-parallel-computing-in-go-a-practical-approach-with-goroutines-waitgroups-mutexes-and-atomic-operations-4agk</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Parallelism Fundamentals in Go: Learn how to Implement Goroutines and WaitGroups to Run Tasks Concurrently&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A fundamental technique for improving performance is &lt;strong&gt;parallel computing&lt;/strong&gt;, which allows multiple tasks to run simultaneously to make the best use of system resources. In this blog, we will explore how to implement parallel programming techniques in Go, using practical examples and key concepts such as &lt;strong&gt;goroutines, WaitGroups, Mutexes and atomic operations&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction to Parallel Computing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Parallel computing&lt;/strong&gt; is a form of processing in which tasks are divided into sub-tasks that can be executed at the same time. This contrasts with &lt;strong&gt;sequential computing&lt;/strong&gt;, where tasks are executed one after the other. The main idea is that by executing multiple operations simultaneously, the overall execution time can be reduced and the overall efficiency of the system can be improved.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parallelism vs. Concurrency
&lt;/h3&gt;

&lt;p&gt;It is important to differentiate between &lt;strong&gt;parallelism&lt;/strong&gt; and &lt;strong&gt;concurrency&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Parallelism:&lt;/strong&gt; This refers to the simultaneous execution of multiple tasks. In the context of computing, this generally involves the use of multiple CPU cores to execute tasks at the same time. In Go, this is achieved through the use of goroutines and the thread-based execution model.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Concurrency:&lt;/strong&gt; The ability to handle multiple tasks in such a way that they appear to be running simultaneously, even if they are not necessarily running in parallel. Concurrency can involve switching between tasks on a single CPU core. In Go, concurrency is handled by goroutines and channels, facilitating the creation of programs that can do multiple things at once.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Parallel Computing in Go
&lt;/h3&gt;

&lt;p&gt;Go, known for its simplicity and efficiency, offers powerful tools for parallel programming. Among them, goroutines are fundamental. &lt;strong&gt;Goroutines&lt;/strong&gt; are functions that run concurrently with other functions. They are lightweight and managed by the Go runtime, allowing highly parallelised applications to be created without additional complications.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Goroutines:&lt;/strong&gt; These are the basic unit of execution in Go. They are created using the &lt;code&gt;go&lt;/code&gt; keyword, and the Go runtime handles the concurrent and parallel execution of these goroutines.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;WaitGroups:&lt;/strong&gt; These are used to wait for a set of goroutines to finish execution. They provide a form of synchronisation between goroutines, ensuring that all parallel tasks complete before continuing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mutexes:&lt;/strong&gt; These are mechanisms to control concurrent access to shared resources. They prevent race condition problems, where two or more goroutines attempt to access and modify the same resource simultaneously, which can lead to unexpected results or errors.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this blog, we will use a practical example of parallel processing in Go to illustrate these concepts. Through the analysis of code that performs parallel mapping, filtering and reduction operations, we will see how to apply these concepts to improve performance and efficiency in Go applications. We will explore how goroutines and other tools provided by the language can be used to achieve faster and more efficient data processing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Components in the Code
&lt;/h2&gt;

&lt;p&gt;In this section, we will discuss in detail the essential components of our code, explaining how goroutines, &lt;code&gt;sync.WaitGroup&lt;/code&gt;, &lt;code&gt;sync.Mutex&lt;/code&gt; and atomic operations are used to implement parallel programming in Go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can find the complete code here:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/MateoRamirezRubio1" rel="noopener noreferrer"&gt;
        MateoRamirezRubio1
      &lt;/a&gt; / &lt;a href="https://github.com/MateoRamirezRubio1/learning_Go_Golang" rel="noopener noreferrer"&gt;
        learning_Go_Golang
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Goroutines
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Goroutines&lt;/strong&gt; are a fundamental feature of Go that allows concurrent execution of functions. They are created by using the &lt;code&gt;go&lt;/code&gt; keyword before a function or function expression. Goroutines are lightweight and managed by the Go runtime, which means that they can be created and managed in large numbers without a high resource cost.&lt;/p&gt;

&lt;p&gt;In the code, goroutines are used to perform parallel operations on different parts of a slice. This is done in the &lt;code&gt;parallelMap&lt;/code&gt;, &lt;code&gt;parallelFilter&lt;/code&gt;, and &lt;code&gt;parallelReduce&lt;/code&gt; functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Each worker applies the mapping function to its chunk of the slice.&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mapFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Each goroutine takes a segment of the &lt;code&gt;nums&lt;/code&gt; slice and applies the &lt;code&gt;mapFunc&lt;/code&gt; function to each element of that segment. The use of goroutines allows multiple segments of the slice to be processed at the same time, reducing the overall execution time.&lt;/p&gt;
&lt;h3&gt;
  
  
  WaitGroups
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;sync.WaitGroup&lt;/code&gt; is a synchronisation tool used to wait for a group of goroutines to complete their execution. It is used to coordinate the completion of multiple goroutines and ensure that all goroutines have finished before continuing the execution of the program.&lt;/p&gt;

&lt;p&gt;In the code, &lt;code&gt;sync.WaitGroup&lt;/code&gt; is used to ensure that the main program waits for all goroutines to finish before continuing:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Create a WaitGroup to synchronize the workers.&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

    &lt;span class="c"&gt;// Start the workers.&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;chunkSize&lt;/span&gt;
        &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;chunkSize&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;// Each worker applies the mapping function to its chunk of the slice.&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mapFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Wait for all workers to finish.&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here, &lt;code&gt;wg.Add(1)&lt;/code&gt; increments the WaitGroup counter each time a new goroutine is started. Each goroutine calls &lt;code&gt;wg.Done()&lt;/code&gt; when it finishes, decrementing the counter. &lt;code&gt;wg.Wait()&lt;/code&gt; blocks the main thread until the counter reaches zero, i.e. until all goroutines have finished their work.&lt;/p&gt;
&lt;h3&gt;
  
  
  Mutexes
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;sync.Mutex&lt;/code&gt; is a synchronisation mechanism used to prevent race conditions, which occur when multiple goroutines attempt to access and modify shared data at the same time. A mutex ensures that only one goroutine can access a critical section of code at a time.&lt;/p&gt;

&lt;p&gt;In the code, &lt;code&gt;sync.mutex&lt;/code&gt; is used to protect access to the &lt;code&gt;result&lt;/code&gt; slice during filtering and reduction operations:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Create a Mutex to protect the result slice.&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mu&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;

&lt;span class="c"&gt;// Each worker filters its chunk of the slice and appends the results to the local result slice.&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;localResult&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;filterFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;localResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c"&gt;// Lock the Mutex and append the local result slice to the global result slice.&lt;/span&gt;
            &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;localResult&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The mutex &lt;code&gt;mu&lt;/code&gt; is used to ensure that only one goroutine can modify &lt;code&gt;result&lt;/code&gt; at any given time. &lt;code&gt;mu.Lock()&lt;/code&gt; acquires the mutex before modifying &lt;code&gt;result&lt;/code&gt;, and &lt;code&gt;mu.Unlock()&lt;/code&gt; releases the mutex after the modification.&lt;/p&gt;
&lt;h3&gt;
  
  
  Atomic Operations
&lt;/h3&gt;

&lt;p&gt;Atomic operations allow operations on shared variables to be performed safely without the need for mutexes. The &lt;code&gt;sync/atomic&lt;/code&gt; package provides operations such as addition, subtraction, and compare and shift, which are atomic and ensure that operations are safe in a concurrent environment.&lt;/p&gt;

&lt;p&gt;In the code, &lt;code&gt;atomic.AddInt32&lt;/code&gt; is used to perform the reduction safely:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt;

&lt;span class="c"&gt;// Each worker reduces its chunk of the slice and atomically adds the result to the global result variable.&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;localResult&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;localResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reduceFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c"&gt;// Lock the Mutex and atomically add the local result to the global result variable.&lt;/span&gt;
            &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddInt32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localResult&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here, &lt;code&gt;atomic.AddInt32(&amp;amp;result, int32(localResult))&lt;/code&gt; adds the &lt;code&gt;localResult&lt;/code&gt; value to the &lt;code&gt;result&lt;/code&gt; variable atomically, avoiding synchronisation problems without the need to use a mutex.&lt;/p&gt;


&lt;h2&gt;
  
  
  Parallel Execution in Action: Mapping, Filtering and Reduction
&lt;/h2&gt;

&lt;p&gt;Now, we will examine how mapping, filtering, and reduction operations are implemented in parallel using goroutines, &lt;code&gt;sync.WaitGroup&lt;/code&gt;, &lt;code&gt;sync.Mutex&lt;/code&gt;, and atomic operations. These operations are common in data processing and benefit greatly from parallel programming to improve performance.&lt;/p&gt;
&lt;h3&gt;
  
  
  Parallel Mapping
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Mapping&lt;/strong&gt; is the process of applying a function to each element of a data set and transforming those elements into new values. In the code provided, &lt;code&gt;parallelMap&lt;/code&gt; performs this operation in parallel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// parallelMap applies a mapping function to each element of a slice in parallel.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;parallelMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mapFunc&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// Create a result slice of the same length as the input slice.&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// Calculate the chunk size for each worker.&lt;/span&gt;
    &lt;span class="n"&gt;chunkSize&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt;
    &lt;span class="c"&gt;// Create a WaitGroup to synchronize the workers.&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

    &lt;span class="c"&gt;// Start the workers.&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;chunkSize&lt;/span&gt;
        &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;chunkSize&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;// Each worker applies the mapping function to its chunk of the slice.&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mapFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Wait for all workers to finish.&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Creating the Result Slice:&lt;/strong&gt; A &lt;code&gt;result&lt;/code&gt; slice is created with the same length as the &lt;code&gt;nums&lt;/code&gt; input slice. This slice will store the mapping results.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Division of Labour:&lt;/strong&gt; The chunk size for each goroutine is calculated as &lt;code&gt;n / numWorkers&lt;/code&gt;. Each goroutine will process a section of the &lt;code&gt;nums&lt;/code&gt; slice, from index &lt;code&gt;start&lt;/code&gt; to &lt;code&gt;end&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Launching Goroutines:&lt;/strong&gt; A goroutine is started for each slice segment. Each goroutine applies the &lt;code&gt;mapFunc&lt;/code&gt; function to its segment of &lt;code&gt;nums&lt;/code&gt; and stores the result in &lt;code&gt;result&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Synchronisation:&lt;/strong&gt; &lt;code&gt;sync.WaitGroup&lt;/code&gt; is used to wait for all goroutines to finish. &lt;code&gt;wg.Add(1)&lt;/code&gt; is called before starting each goroutine, and &lt;code&gt;wg.Done()&lt;/code&gt; is called at the end.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Wait for Completion:&lt;/strong&gt; &lt;code&gt;wg.Wait()&lt;/code&gt; blocks execution until all goroutines have finished their work, ensuring that &lt;code&gt;result&lt;/code&gt; is completely filled with mapped values.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Parallel Filtering
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Filtering&lt;/strong&gt; is the process of selecting elements from a dataset that meet a specific condition. In &lt;code&gt;parallelFilter&lt;/code&gt;, this process is done in parallel to improve performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// parallelFilter filters a slice in parallel using a filtering function.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;parallelFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filterFunc&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;chunkSize&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;
    &lt;span class="c"&gt;// Create a Mutex to protect the result slice.&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mu&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;chunkSize&lt;/span&gt;
        &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;chunkSize&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;// Each worker filters its chunk of the slice and appends the results to the local result slice.&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;localResult&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;filterFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;localResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c"&gt;// Lock the Mutex and append the local result slice to the global result slice.&lt;/span&gt;
            &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;localResult&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Wait for all workers to finish.&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Creating the Result Slice:&lt;/strong&gt; A &lt;code&gt;result&lt;/code&gt; slice is created which is initially empty. This slice will store the elements that pass the filter.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Division of Labour:&lt;/strong&gt; Each goroutine processes a section of the &lt;code&gt;nums&lt;/code&gt; slice, applying the &lt;code&gt;filterFunc&lt;/code&gt; function to select the elements that meet the condition. Accumulation of&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Local Results:&lt;/strong&gt; Each goroutine maintains a local slice &lt;code&gt;localResult&lt;/code&gt; to temporarily store the elements that pass the filter. This avoids data contention between goroutines.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mutex Access Protection:&lt;/strong&gt; After a goroutine completes its filtering, it uses &lt;code&gt;mu.Lock()&lt;/code&gt; to ensure exclusive access to the &lt;code&gt;result&lt;/code&gt; slice and aggregate the filtered items. &lt;code&gt;mu.Unlock()&lt;/code&gt; releases the mutex after the operation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Synchronisation:&lt;/strong&gt; &lt;code&gt;sync.WaitGroup&lt;/code&gt; is used to wait for all goroutines to finish. &lt;code&gt;wg.Add(1)&lt;/code&gt; is called before starting each goroutine, and &lt;code&gt;wg.Done()&lt;/code&gt; is called at the end.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Wait for Completion:&lt;/strong&gt; &lt;code&gt;wg.Wait()&lt;/code&gt; ensures that &lt;code&gt;result&lt;/code&gt; is completely filled before returning it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Parallel Reduction
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Reduction&lt;/strong&gt; is the process of combining all elements of a dataset into a single value using a reduce function. In &lt;code&gt;parallelReduce&lt;/code&gt;, this process is performed in parallel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// parallelReduce reduces a slice in parallel using a reduction function.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;parallelReduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reduceFunc&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;chunkSize&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mu&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;chunkSize&lt;/span&gt;
        &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;chunkSize&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;// Each worker reduces its chunk of the slice and atomically adds the result to the global result variable.&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;localResult&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;localResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reduceFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c"&gt;// Lock the Mutex and atomically add the local result to the global result variable.&lt;/span&gt;
            &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddInt32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localResult&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Wait for all workers to finish.&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Result initialisation:&lt;/strong&gt; &lt;code&gt;result&lt;/code&gt; is a variable of type &lt;code&gt;int32&lt;/code&gt; that is used to store the final accumulated value. It is initialised with a default value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Division of Labour:&lt;/strong&gt; Each goroutine processes a segment of the &lt;code&gt;nums&lt;/code&gt; slice, applying the &lt;code&gt;reduceFunc&lt;/code&gt; function to combine the values into a partial result.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Local Result Calculation:&lt;/strong&gt; Each goroutine maintains a &lt;code&gt;localResult&lt;/code&gt; variable to accumulate the partial result of its segment. The &lt;code&gt;reduceFunc&lt;/code&gt; function is applied iteratively to the elements of the segment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Atomic Update:&lt;/strong&gt; After calculating the partial result, &lt;code&gt;atomic.AddInt32&lt;/code&gt; is used to add &lt;code&gt;localResult&lt;/code&gt; to the &lt;code&gt;result&lt;/code&gt; variable atomically. This ensures that the update is safe in a concurrent environment without using a mutex for synchronisation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Synchronisation:&lt;/strong&gt; &lt;code&gt;sync.WaitGroup&lt;/code&gt; is used to wait for all goroutines to finish. &lt;code&gt;wg.Add(1)&lt;/code&gt; is called before starting each goroutine, and &lt;code&gt;wg.Done()&lt;/code&gt; is called on completion.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Wait for Completion:&lt;/strong&gt; &lt;code&gt;wg.Wait()&lt;/code&gt; blocks until all goroutines have finished, ensuring that &lt;code&gt;result&lt;/code&gt; contains the final accumulated value.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  Detailed Explanation of main
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;main()&lt;/code&gt; is the main function in a Go program, and in this case, it coordinates the execution of parallel processing in the program. In the following, we will break down each part of main to understand how it works and what its purpose is.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;### Data Generation
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Generate a random slice of 1000000 integers between 1 and 9.&lt;/span&gt;
&lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;generateRandomSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"First numbers:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Generation:&lt;/strong&gt; The &lt;code&gt;generateRandomSlice&lt;/code&gt; function is used to create a 1,000,000 slice of random integers in the range 1 to 9. This slice simulates a large data set to process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Print First Numbers:&lt;/strong&gt; A portion of the slice (&lt;code&gt;nums[:10]&lt;/code&gt;) is printed to show the first 10 numbers generated. This is useful to verify that the data generation was successful.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;### Measuring Execution Time
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Start measuring execution time.&lt;/span&gt;
&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Measurement Start:&lt;/strong&gt; &lt;code&gt;time.Now()&lt;/code&gt; is used to capture the current time, marking the start of the measurement of parallel processing execution time. This will allow to calculate how long it takes to complete all parallel operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;### Configuring the Number of Workers
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Get the number of CPUs available.&lt;/span&gt;
&lt;span class="n"&gt;numWorkers&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NumCPU&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Number of Workers:&lt;/strong&gt; &lt;code&gt;runtime.NumCPU()&lt;/code&gt; returns the number of CPU cores available on the machine. This value is used to define how many workers (goroutines) will be used in parallel processing. Using a number equal to the number of CPU cores helps to optimise performance. In the next section when we run the code we will go more into this.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;### Application of Parallel Functions
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Apply the mapping function in parallel.&lt;/span&gt;
&lt;span class="n"&gt;mapped&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;parallelMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application of parallelMap:&lt;/strong&gt; The &lt;code&gt;parallelMap&lt;/code&gt; function is called to apply a mapping function to each element of the slice nums. In this case, the mapping function multiplies each number by 2.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Apply the filtering function in parallel.&lt;/span&gt;
&lt;span class="n"&gt;filtered&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;parallelFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapped&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application of parallelFilter:&lt;/strong&gt; The &lt;code&gt;parallelFilter&lt;/code&gt; function is called to filter the mapped slice, keeping only elements greater than 10.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Apply the reduction function in parallel.&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;parallelReduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;numWorkers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application of parallelReduce:&lt;/strong&gt; The &lt;code&gt;parallelReduce&lt;/code&gt; function is called to reduce the filtered slice by summing all elements. The reduce function takes an accumulator and an element, and returns their sum.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;### Printout of Results
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Result:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Print Result:&lt;/strong&gt; The final result of the reduction is printed. This is the aggregated value of all elements that passed the filter.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;### Measuring Execution Time
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Stop measuring execution time and print the duration.&lt;/span&gt;
&lt;span class="n"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Since&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Execution time:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;End of Measurement:&lt;/strong&gt; &lt;code&gt;time.Since(start)&lt;/code&gt; calculates the duration from the start of parallel processing to the current time. This duration is printed to show how long it took to perform all parallel operations.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Examples of results and numWorkers
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;numWorkers&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NumCPU&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The line &lt;code&gt;numWorkers := runtime.NumCPU()&lt;/code&gt; is a key part of the code that allocates the number of workers to be used to process tasks in parallel. This line uses the &lt;code&gt;runtime.NumCPU()&lt;/code&gt; function, which returns the number of CPU cores available on the system where the program is running. This number is then assigned to &lt;code&gt;numWorkers&lt;/code&gt;, which determines how many goroutines will be created to split the work.&lt;/p&gt;
&lt;h3&gt;
  
  
  Use Cases and Considerations
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Parallelism Optimisation:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **CPU Leverage:** By using `runtime.NumCPU()`, the code attempts to take full advantage of the available hardware by allocating one goroutine per CPU core. This can improve performance by distributing the workload across all cores, allowing multiple tasks to run in parallel without saturating a single core.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Avoid Goroutine Overload:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Worker/Task Balance:** If `numWorkers` is equal to or close to `runtime.NumCPU()`, the program is likely to maintain an appropriate balance between the number of workers and system capabilities. However, if this number is significantly exceeded, performance may suffer due to system overhead from creating and managing too many goroutines, which can lead to unnecessary competition for system resources.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Problems with Small Data Sizes:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **More Workers than Tasks:** If the number of workers (`numWorkers`) is greater than the number of elements in the array, a problem can occur. For example, if you have an array with 4 elements and `numWorkers` is 8 (assuming the CPU has 8 cores), some goroutines will not have enough elements to process. This can cause incorrect or inefficient behaviour, such as:

    * **Resource Waste:** Some goroutines may end up not doing any useful work, which wastes system resources.

    * **Incorrect results:** Depending on how the code is structured, if the work is divided into more goroutines than elements in the array, some goroutines might not process any data, which could lead to incorrect results.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Manual Tuning of numWorkers:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Optimisation for Specific Data:** In some cases, it may be beneficial to manually set `numWorkers` instead of using `runtime.NumCPU()`. For example, if you know the array size is small, you can set `numWorkers` to a lower number to avoid over-allocating goroutines. This can result in more efficient code that is easier to debug.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Behaviour with Very Large Arrays:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Equal Division of Labor:** When working with very large arrays, `runtime.NumCPU()` can help ensure that each CPU core gets a reasonable share of the work. This is especially useful in intensive operations where parallelism can significantly reduce execution time.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Practical Example
&lt;/h3&gt;

&lt;p&gt;Suppose you are running code on a system with 8 CPU cores (&lt;code&gt;runtime.NumCPU()&lt;/code&gt; returns 8). If you have an array with 100 elements, and you use &lt;code&gt;numWorkers := 8&lt;/code&gt;, each goroutine will process 12 or 13 elements (100/8 = 12.5). This is usually efficient.&lt;/p&gt;

&lt;p&gt;However, if the array has only 4 elements and &lt;code&gt;numWorkers&lt;/code&gt; is still 8, then each goroutine will handle half an element, which is impractical and may cause some goroutines to do nothing, or even throw errors if the code does not handle this scenario correctly.&lt;/p&gt;


&lt;h2&gt;
  
  
  Execution and result verification
&lt;/h2&gt;

&lt;p&gt;To:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;generateRandomSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"First numbers:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c"&gt;// Start measuring execution time.&lt;/span&gt;
&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c"&gt;// Get the number of CPUs available.&lt;/span&gt;
&lt;span class="n"&gt;numWorkers&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When running the code with the command &lt;code&gt;go run parallel_map_filter_reduce.go&lt;/code&gt;, with the above parameters set in the &lt;code&gt;main()&lt;/code&gt;, we get in console:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;First numbers: &lt;span class="o"&gt;[&lt;/span&gt;3 6 1 2 8 1 7 2 8 6]
Result: 70
Execution &lt;span class="nb"&gt;time&lt;/span&gt;: 514.3µs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Execution Explanation
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Random Slice Generation:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* `generateRandomSlice(10, 1, 9)` generates a slice of 10 random integers, each within the range of 1 to 9.

* In this particular run, the numbers generated were: `[3, 6, 1, 2, 2, 8, 1, 7, 2, 8, 6]`.

* This line also prints the numbers generated: First numbers: `[3 6 1 2 8 1 7 2 8 6]`.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Number of Workers:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* We define `numWorkers := 3`, indicating that 3 goroutines (workers) will be used to process the slice in parallel.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Execution Result:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* The code processed the generated slice using the parallel mapping, filtering and reduction functions.

* The final result was `70`.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Checking the Result
&lt;/h3&gt;

&lt;p&gt;Let's check the result step by step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Mapping (Multiplication by 2):&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* The numbers `[3, 6, 1, 2, 2, 8, 1, 7, 2, 8, 6]` are mapped to `[6, 12, 2, 4, 16, 2, 14, 4, 16, 12]`.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Filtering (Greater than 10):&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* Numbers greater than 10 are filtered out, leaving `[12, 16, 14, 16, 16, 12]`.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Reduction (Sum):&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* The sum of the filtered numbers is `12 + 16 + 14 + 16 + 16 + 12 = 70`.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The result obtained (&lt;code&gt;70&lt;/code&gt;) is correct, as it corresponds to the sum of the values that passed the filter after being mapped.&lt;/p&gt;
&lt;h3&gt;
  
  
  Warning about &lt;code&gt;numWorkers&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;When using &lt;code&gt;numWorkers&lt;/code&gt;, it is important to choose an appropriate value for the number of workers in relation to the size of the slice. Here are some warnings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Too many Workers:&lt;/strong&gt; if &lt;code&gt;numWorkers&lt;/code&gt; is greater than the number of elements in the slice, some workers will have no work, which could cause parallelism to be inefficient. This can also lead to problems if the code does not handle these cases correctly, as happened in the example above with an incorrect result.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Too Few Workers:&lt;/strong&gt; If the number of workers is too low, parallelism will not be properly exploited, which could cause the program to run slower than if more workers were used.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this case, with &lt;code&gt;numWorkers := 3&lt;/code&gt; for a 10-element slice, each worker processes approximately 3-4 elements, which is reasonable and results in correct processing.&lt;/p&gt;


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

&lt;p&gt;We have explored the fascinating world of parallel computing in Go, focusing on how to take advantage of the language's features to improve the efficiency and performance of our applications. Through a practical example that performs parallel mapping, filtering and reduction operations, we have seen how goroutines, WaitGroups and Mutexes can be used to handle concurrent tasks and synchronise access to shared resources.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;How would you improve this code to make it even more efficient or robust?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Your perspective can help to further optimise the code and adapt it to new situations.&lt;/p&gt;

&lt;p&gt;I look forward to hearing from you in the comments.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;You may be interested:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/mateoramirezr" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1743449%2F4f728917-8640-49d2-954f-8bf7f5026fa1.png" alt="mateoramirezr"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mateoramirezr/mastering-testing-in-django-rest-framework-from-pytest-and-fixtures-to-mocks-and-coverage-4jg6" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Mastering Testing in Django REST Framework: From Pytest and Fixtures to Mocks and Coverage&lt;/h2&gt;
      &lt;h3&gt;Mateo Ramirez Rubio ・ Jul 22&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#testing&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#programming&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Using Environment Variables with flutter_dotenv and DotEnv in Flutter: Step by Step Guide</title>
      <dc:creator>Mateo Ramirez Rubio</dc:creator>
      <pubDate>Tue, 06 Aug 2024 05:10:08 +0000</pubDate>
      <link>https://forem.com/mateoramirezr/using-environment-variables-with-flutterdotenv-and-dotenv-in-flutter-step-by-step-guide-4n8g</link>
      <guid>https://forem.com/mateoramirezr/using-environment-variables-with-flutterdotenv-and-dotenv-in-flutter-step-by-step-guide-4n8g</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Load and access your environment variables securely and efficiently in your Flutter applications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When building Flutter applications, it's essential to manage sensitive data like API keys, database credentials, or environment-specific configurations. Hardcoding these values directly in your code is a security risk and can lead to issues when deploying your app to different environments.&lt;/p&gt;

&lt;p&gt;That's where &lt;code&gt;.env&lt;/code&gt; variables come in – a simple and effective way to store and manage environment-specific configurations. In this blog, we’ll explore how to use &lt;code&gt;.env&lt;/code&gt; files to manage environment variables in your Flutter app, with a step-by-step guide and a practical example.&lt;/p&gt;




&lt;h2&gt;
  
  
  Some concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What Are &lt;code&gt;.env&lt;/code&gt; Files?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;.env&lt;/code&gt; files are simple text files used to store environment-specific variables. They typically contain key-value pairs, like API keys or base URLs, which can be accessed throughout your application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Use &lt;code&gt;.env&lt;/code&gt; Files?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Separation of Concerns&lt;/strong&gt;: Keep configuration settings separate from your code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;: Store sensitive information like API keys securely.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;: Easily switch between different environments (development, staging, production).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Step-by-Step Guide&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before we begin, ensure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Flutter project set up.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Add the &lt;code&gt;dotenv&lt;/code&gt; package
&lt;/h3&gt;

&lt;p&gt;First, add the &lt;code&gt;dotenv&lt;/code&gt; package to your &lt;code&gt;pubspec.yaml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;flutter_dotenv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^5.1.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 2: Create a &lt;code&gt;.env&lt;/code&gt; File
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in the root directory of your Flutter project. This file will store your environment variables.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_api_key_here
&lt;span class="nv"&gt;BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 3: Update &lt;code&gt;pubspec.yaml&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Ensure that the &lt;code&gt;.env&lt;/code&gt; file is included as an asset in your project. Modify your &lt;code&gt;pubspec.yaml&lt;/code&gt; file to include the &lt;code&gt;.env&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;flutter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;assets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Run &lt;code&gt;flutter pub get&lt;/code&gt; to apply the changes.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 4: Load the &lt;code&gt;.env&lt;/code&gt; File
&lt;/h3&gt;

&lt;p&gt;In your &lt;code&gt;main.dart&lt;/code&gt; file, import &lt;code&gt;flutter_dotenv&lt;/code&gt; and load the &lt;code&gt;.env&lt;/code&gt; file before running the app:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_dotenv/flutter_dotenv.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;WidgetsFlutterBinding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ensureInitialized&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Ensure Flutter is initialized&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;fileName:&lt;/span&gt; &lt;span class="s"&gt;".env"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Load environment variables&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Error loading .env file: &lt;/span&gt;&lt;span class="si"&gt;$e&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Print error if any&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MainApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// Runs the app&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ensure Flutter is initialized&lt;/strong&gt;: &lt;code&gt;WidgetsFlutterBinding.ensureInitialized()&lt;/code&gt; ensures that Flutter's framework is initialized before loading the &lt;code&gt;.env&lt;/code&gt; file. This is important because &lt;code&gt;dotenv.load()&lt;/code&gt; relies on Flutter's file system to read the &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Load environment variables&lt;/strong&gt;: &lt;code&gt;await dotenv.load(fileName: ".env")&lt;/code&gt; loads the environment variables from the &lt;code&gt;.env&lt;/code&gt; file. The &lt;code&gt;await&lt;/code&gt; keyword ensures that the loading process is completed before proceeding.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error handling&lt;/strong&gt;: The &lt;code&gt;try-catch&lt;/code&gt; block catches any errors that might occur while loading the &lt;code&gt;.env&lt;/code&gt; file. If an error occurs, it throws an exception with a meaningful error message.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Run the app&lt;/strong&gt;: Finally, &lt;code&gt;runApp(const MainApp())&lt;/code&gt; runs the app.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Step 5: Access Environment Variables
&lt;/h2&gt;

&lt;p&gt;You can access the environment variables using &lt;code&gt;dotenv.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_dotenv/flutter_dotenv.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApiService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;baseUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'BASE_URL'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s"&gt;'default_url'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'API_KEY'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s"&gt;'default_key'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Use baseUrl and apiKey in your API calls&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Common Issues:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File Not Found&lt;/strong&gt;: Ensure the &lt;code&gt;.env&lt;/code&gt; file is in the root directory and correctly specified in &lt;code&gt;pubspec.yaml&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File Not Loading&lt;/strong&gt;: Confirm that &lt;code&gt;await dotenv.load()&lt;/code&gt; is called before running the app.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/strong&gt; Remember to add your &lt;code&gt;.env&lt;/code&gt; file to your &lt;code&gt;.gitignore&lt;/code&gt; file to avoid committing sensitive data to your version control system.&lt;/p&gt;



&lt;p&gt;By following these steps and using &lt;code&gt;flutter_dotenv&lt;/code&gt; in your Flutter app, you'll be able to manage your environment-specific configurations securely and efficiently.&lt;/p&gt;

&lt;p&gt;I hope this helps! Let me know if you have any questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aditional Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pub.dev/packages/flutter_dotenv" rel="noopener noreferrer"&gt;Flutter Dotenv documentation.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Topics you may be interested in:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/mateoramirezr" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1743449%2F4f728917-8640-49d2-954f-8bf7f5026fa1.png" alt="mateoramirezr"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mateoramirezr/mastering-testing-in-django-rest-framework-from-pytest-and-fixtures-to-mocks-and-coverage-4jg6" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Mastering Testing in Django REST Framework: From Pytest and Fixtures to Mocks and Coverage&lt;/h2&gt;
      &lt;h3&gt;Mateo Ramirez Rubio ・ Jul 22&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#testing&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#programming&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;




&lt;div class="ltag__link"&gt;
  &lt;a href="/mateoramirezr" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1743449%2F4f728917-8640-49d2-954f-8bf7f5026fa1.png" alt="mateoramirezr"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mateoramirezr/how-to-name-endpoints-in-a-rest-api-complete-guide-with-best-practices-and-practical-example-1c3l" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;How to Name Endpoints in a REST API: Complete Guide with Best Practices and Practical Example&lt;/h2&gt;
      &lt;h3&gt;Mateo Ramirez Rubio ・ Jul 7&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#api&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#rest&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#backend&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>flutter</category>
      <category>dart</category>
      <category>mobile</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Mastering Testing in Django REST Framework: From Pytest and Fixtures to Mocks and Coverage</title>
      <dc:creator>Mateo Ramirez Rubio</dc:creator>
      <pubDate>Mon, 22 Jul 2024 11:05:21 +0000</pubDate>
      <link>https://forem.com/mateoramirezr/mastering-testing-in-django-rest-framework-from-pytest-and-fixtures-to-mocks-and-coverage-4jg6</link>
      <guid>https://forem.com/mateoramirezr/mastering-testing-in-django-rest-framework-from-pytest-and-fixtures-to-mocks-and-coverage-4jg6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this blog we'll see a basic guide on how to test a Django project using the Django REST Framework! Here, we'll learn the basics of testing with pytest, including essential concepts such as fixtures and mocks, to test execution and test coverage with coverage.&lt;/p&gt;

&lt;p&gt;This is the second part of a project we have already done in the blog, in this blog we will do the testing of this project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can see how the code base of the Django project was developed step by step with the Django REST framework here:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/mateoramirezr" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1743449%2F4f728917-8640-49d2-954f-8bf7f5026fa1.png" alt="mateoramirezr"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mateoramirezr/complete-guide-to-the-django-services-and-repositories-design-pattern-with-the-django-rest-framework-37c7" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Complete Guide to the Django Services and Repositories Design Pattern with the Django REST Framework&lt;/h2&gt;
      &lt;h3&gt;Mateo Ramirez Rubio ・ Jul 8&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#django&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#backend&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#api&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
 


&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;p&gt;In this guide we will cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Initial Setup:&lt;/strong&gt; How to install and configure &lt;code&gt;pytest&lt;/code&gt; and other packages needed to test your Django project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fixtures:&lt;/strong&gt; How to use fixtures to set up test data and prepare the test environment efficiently.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mocks:&lt;/strong&gt; How to use &lt;code&gt;pytest-mock&lt;/code&gt; to simulate behaviours and conditions in your tests, ensuring that you can test different scenarios without relying on real implementations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Model Testing:&lt;/strong&gt; We will verify the creation of model instances and their string representations to ensure they work as expected.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Repository Testing:&lt;/strong&gt; We will test the operation of repository methods, including database manipulation and error handling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;API View Testing:&lt;/strong&gt; We will validate that API views respond correctly to HTTP requests and handle data properly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Web View Testing:&lt;/strong&gt; We will ensure that web views load correctly and display the expected content.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Code Coverage:&lt;/strong&gt; We will run tests and generate coverage reports to identify areas of the code that need further testing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Recommendations, Test Types and Best Practices.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will look at practical examples of configuring files such as pytest.ini and demonstrate how to run the commands to get detailed coverage reports with coverage.&lt;/p&gt;


&lt;h2&gt;
  
  
  Introduction to Testing with Pytest
&lt;/h2&gt;

&lt;p&gt;Testing is a crucial part of software development that ensures the quality, functionality and reliability of code. In the Python ecosystem, &lt;code&gt;pytest&lt;/code&gt; is one of the most popular and powerful tools for testing.&lt;/p&gt;
&lt;h3&gt;
  
  
  What is Pytest?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pytest&lt;/code&gt; is a Python testing framework that makes it easy to write simple, scalable tests. It is known for its simplicity and its ability to adapt to projects of any size. With pytest, you can write unit tests, integration tests, and more, using a clear and concise syntax.&lt;/p&gt;
&lt;h3&gt;
  
  
  Advantages of Using Pytest:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplicity and Flexibility:&lt;/strong&gt;&lt;code&gt;pytest&lt;/code&gt; allows you to write tests using simple functions. You don't need to learn a complex syntax or follow a rigid structure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Powerful Fixtures:&lt;/strong&gt;&lt;code&gt;pytest&lt;/code&gt; provides a fixture system that allows you to configure the state before and after testing, making it easy to create repeatable and isolated test environments (more on fixtures later in the blog).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Extensible Plugins:&lt;/strong&gt;&lt;code&gt;pytest&lt;/code&gt; has a lot of plugins that extend its functionality, such as &lt;code&gt;pytest-django&lt;/code&gt; for Django projects, &lt;code&gt;pytest-mock&lt;/code&gt; for mocks and many more.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clear Error Reporting:&lt;/strong&gt; Error messages in &lt;code&gt;pytest&lt;/code&gt; are detailed and easy to understand, which helps to identify and fix problems quickly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automatic Test Detection:&lt;/strong&gt;&lt;code&gt;pytest&lt;/code&gt; automatically detects tests in your project without the need to explicitly record them, which simplifies test organisation.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Integration with Django
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pytest&lt;/code&gt; integrates easily with Django through the &lt;code&gt;pytest-django&lt;/code&gt; plugin. This allows you to efficiently test views, models and other components of a Django project. With &lt;code&gt;pytest-django&lt;/code&gt;, you can use Django-specific fixtures, such as the test database, users and more.&lt;/p&gt;


&lt;h2&gt;
  
  
  Initial setup for Testing with Pytest in a Django project with Django REST Framework
&lt;/h2&gt;

&lt;p&gt;Before starting to write and run tests with &lt;code&gt;pytest&lt;/code&gt; in a Django project, it is essential to properly configure the test environment.&lt;/p&gt;
&lt;h3&gt;
  
  
  Installing the requirements
&lt;/h3&gt;

&lt;p&gt;To install the &lt;code&gt;pytest&lt;/code&gt;, &lt;code&gt;pytest-django&lt;/code&gt;, &lt;code&gt;beautifulsoup4&lt;/code&gt;, &lt;code&gt;coverage&lt;/code&gt; and &lt;code&gt;pytest-mock&lt;/code&gt; dependencies, follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a virtual environment (optional but recommended):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; venv &lt;span class="nb"&gt;env
source env&lt;/span&gt;/bin/activate
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Install the dependencies using pip:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pytest pytest-django beautifulsoup4 coverage pytest-mock
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Little explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;pytest:&lt;/strong&gt; The core testing framework.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;pytest-django:&lt;/strong&gt; Plugin that makes it easy to integrate pytest with Django.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;beautifulsoup4:&lt;/strong&gt; Used to parse and check HTML in view tests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;coverage:&lt;/strong&gt; Tool to measure test coverage, ensuring that all parts of the code are tested.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;pytest-mock:&lt;/strong&gt; Plugin to facilitate the creation and use of mocks in tests.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pytest configuration
&lt;/h2&gt;

&lt;p&gt;To configure &lt;code&gt;pytest&lt;/code&gt; in a Django project, we need to create a &lt;code&gt;pytest.ini&lt;/code&gt; file in the root directory of the project. This file will define the specific &lt;code&gt;pytest&lt;/code&gt; settings.&lt;/p&gt;

&lt;p&gt;Create a file called &lt;code&gt;pytest.ini&lt;/code&gt; in the root directory of your Django project and add the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;DJANGO_SETTINGS_MODULE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_project_blog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;
&lt;span class="n"&gt;python_files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;test_&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;_tests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DJANGO_SETTINGS_MODULE:&lt;/strong&gt; Specifies the Django configuration module that &lt;code&gt;pytest&lt;/code&gt; should use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;python_files:&lt;/strong&gt; Defines the filename patterns that &lt;code&gt;pytest&lt;/code&gt; will recognise as test files. In this case, &lt;code&gt;pytest&lt;/code&gt; will look for files named &lt;code&gt;tests.py&lt;/code&gt;, files starting with &lt;code&gt;test_&lt;/code&gt;, and files ending in &lt;code&gt;_tests.py&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Structure
&lt;/h2&gt;

&lt;p&gt;For this project, all the tests of the project will be located in the &lt;code&gt;tests&lt;/code&gt; directory which is located in the apps directory. We will follow the following file structure of the tests for better separation of functions and readability:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshekfh6v37w4btygr09a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshekfh6v37w4btygr09a.png" alt="Structure" width="250" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this blog, we will cover some of the main tests (&lt;em&gt;Note:&lt;/em&gt; We will only look at the main tests as the others have a similar structure), but you can find the full test code here:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/MateoRamirezRubio1" rel="noopener noreferrer"&gt;
        MateoRamirezRubio1
      &lt;/a&gt; / &lt;a href="https://github.com/MateoRamirezRubio1/mini-blog-rest-api" rel="noopener noreferrer"&gt;
        mini-blog-rest-api
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A mini blog Django project demonstrating the implementation of the Services and Repositories design pattern for a blog application.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;This project is a Django-based mini blog application designed to illustrate the implementation of the Services and Repositories design pattern. It features a clear separation of concerns, making the codebase easier to maintain and extend.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You can follow the step by step of the making of the app on my blog: &lt;a href="https://mateoramirezr.hashnode.dev/django-services-and-repositories-design-pattern-with-rest-api" rel="nofollow noopener noreferrer"&gt;My blog&lt;/a&gt;.&lt;/strong&gt;
&lt;br&gt;
&lt;strong&gt;You can see the application test here: &lt;a href="https://mateoramirezr.hashnode.dev/preview/669dcc8df7b0290261679dad" rel="nofollow noopener noreferrer"&gt;Testing App&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Posts and Comments:&lt;/strong&gt; Users can create, update, and delete blog posts and comments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RESTful API:&lt;/strong&gt; Provides endpoints for interacting with the application programmatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Interface:&lt;/strong&gt; Offers a basic user-friendly interface for managing posts and comments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service Layer:&lt;/strong&gt; Contains business logic and orchestrates interactions between views and repositories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository Layer:&lt;/strong&gt; Encapsulates data access logic, providing a clean API for the service layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Django Admin:&lt;/strong&gt; Allows administrative management of posts and comments.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Project Structure&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;The project follows a modular structure, with each app having its own models…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/MateoRamirezRubio1/mini-blog-rest-api" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
 




&lt;h2&gt;
  
  
  Definitions before starting (Fixtures)
&lt;/h2&gt;

&lt;p&gt;In order to get started with the testing, we will create some Fixtures which we will use in several of the tests later on. To give you some context, let's quickly look at what a Fixture is in Pytest.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Fixture?
&lt;/h3&gt;

&lt;p&gt;In the context of testing, a Fixture is a set of data, objects, or configurations that are prepared before running a test.&lt;/p&gt;

&lt;p&gt;Fixtures commonly define the steps and data that constitute the Arrange phase of a test (see the &lt;a href="https://docs.pytest.org/en/stable/explanation/anatomy.html#test-anatomy" rel="noopener noreferrer"&gt;anatomy of a test&lt;/a&gt;), as well as the Cleanup phase using Python's yield statement (&lt;a href="https://docs.pytest.org/en/stable/how-to/fixtures.html#yield-fixtures-recommended" rel="noopener noreferrer"&gt;see more on this&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Basically, test functions request the fixtures they need by declaring them as arguments to the test function where they want to use them. So, when pytest is going to run a test, the first thing it does is look at the parameters that this test function has, and then it looks for fixtures that have the same names as those parameters. Once pytest finds them, it executes them, captures what they return (if anything), and passes those objects to the test function as arguments.&lt;/p&gt;

&lt;p&gt;In order for Pytest to know that a function is a Fixture, we must decorate it with &lt;code&gt;@pytest.fixture&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are fixtures used for?
&lt;/h3&gt;

&lt;p&gt;Fixtures are widely used for different functions, some of these are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prepare the Test Environment:&lt;/strong&gt; Configure the necessary state for testing to be performed under specific conditions. For example, creating objects in the database or initialising configurations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Code Reuse:&lt;/strong&gt; Allows the same set of data or configurations to be used in multiple tests, avoiding code duplication.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test Isolation:&lt;/strong&gt; Ensures that each test runs in a clean and consistent environment, avoiding side effects between tests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configuration Automation:&lt;/strong&gt; Simplifies the automatic configuration of the test environment, ensuring that tests are set up correctly before execution.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Coding Fixtures
&lt;/h2&gt;

&lt;p&gt;Already having some knowledge about what fixtures are, for this case, we will create 4 fixtures which we will set in the &lt;code&gt;conftest.py&lt;/code&gt; file:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Fixture post:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; To create an instance of Post that can be used for testing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reason:&lt;/strong&gt; To test any functionality that involves the Post model, you need an existing Post object in the database. By using a fixture to create this object, you can ensure that each test has a consistent, well-defined Post to work with.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Using fixtures avoids duplication of code in every test that needs a Post, ensuring that all tests that depend on a Post use the same data set.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@pytest.fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Create a Post instance with title and content for testing.

    Args:
        db: The pytest fixture that sets up a test database.

    Returns:
        Post: A Post object with predefined title and content.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Test Post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This is a test post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Fixture comment:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Create an instance of Comment that is associated to a previously created Post.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rationale:&lt;/strong&gt; Similar to the Post case, if your tests involve the Comment model, you need a Comment object in the database. By associating the Comment with a Post, you can test the comment-related functionality of a specific post.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; By using this fixture, you can test how comments interact with posts without having to manually create a Post in each test. It also ensures that the Comment is correctly linked to a Post.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@pytest.fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Create a Comment instance associated with the provided Post.

    Args:
        db: The pytest fixture that sets up a test database.
        post: The Post fixture providing a Post object.

    Returns:
        Comment: A Comment object linked to the provided Post.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This is a test comment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;api_client fixture:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Provide an instance of APIClient to make HTTP requests to API Endpoints.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rationale:&lt;/strong&gt; When testing API views and Endpoints, you need a tool to simulate HTTP requests and receive responses. APIClient is ideal for this because it is designed to interact with API Endpoints and verify responses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Allows you to test API logic, validations, and responses in a controlled test environment. Ensures that the test client is configured consistently for all API testing.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@pytest.fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;api_client&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Provide an instance of APIClient for making API requests.

    Returns:
        APIClient: An instance of the APIClient class.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;APIClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Fixture client:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Provide an instance of the standard Django test client for making HTTP requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rationale:&lt;/strong&gt; In addition to testing the API, you may need to test HTML-based views. Client allows you to perform these tests by simulating HTTP requests and verifying the responses of template-based views.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Allows you to test user interaction with the web application, such as page display and form handling, ensuring that the UI part of the application works correctly.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@pytest.fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Provide a Django test client instance for making HTTP requests.

    Returns:
        Client: An instance of Django&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s test Client class.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Coding the tests
&lt;/h2&gt;

&lt;p&gt;Now that we have everything configured, we'll start testing.&lt;/p&gt;

&lt;p&gt;We'll do it in blocks, first we'll test the Django models, then the repositories, the services, the API REST views and finally the web views.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing the models
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt;&lt;code&gt;test_models.py&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The testing of the models will verify the correct creation and representation of the Post and Comment models, ensuring that the data is handled and presented correctly in different situations.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;test_post_creation(post)&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Verifies that a &lt;code&gt;Post&lt;/code&gt; object is created correctly with the expected title and content.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rationale:&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input:&lt;/strong&gt; Uses the &lt;code&gt;post&lt;/code&gt; fixture, which creates an instance of &lt;code&gt;Post&lt;/code&gt; with predefined data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verification:&lt;/strong&gt; Ensures that the &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;content&lt;/code&gt; attributes of the &lt;code&gt;Post&lt;/code&gt; object match the expected values (‘Test Post’ and ‘This is a test post’, respectively).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; Ensures that the creation of &lt;code&gt;Post&lt;/code&gt; objects works as expected by ensuring that the attributes are set correctly at creation time.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_post_creation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Verify that a Post object is created with the correct title and content.

        Args:
            post: The Post fixture providing a Post object.
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Test Post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This is a test post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;test_comment_creation(comment)&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Verifies that a &lt;code&gt;Comment&lt;/code&gt; object is correctly created with the expected content and that it is associated with the correct Post.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Rationale:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input:&lt;/strong&gt; Uses the &lt;code&gt;comment&lt;/code&gt; fixture, which creates an instance of &lt;code&gt;Comment&lt;/code&gt; linked to a specific Post.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verification:&lt;/strong&gt; Ensures that the &lt;code&gt;content&lt;/code&gt; attribute of the &lt;code&gt;Comment&lt;/code&gt; object is ‘This is a test comment’ and that the associated &lt;code&gt;Post&lt;/code&gt; has the expected title ‘Test Post’.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; Confirms that the comment is correctly associated with the &lt;code&gt;Post&lt;/code&gt; and that the data is stored as expected.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_comment_creation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Verify that a Comment object is created with the correct content and associated Post title.

        Args:
            comment: The Comment fixture providing a Comment object.
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This is a test comment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Test Post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;test_comment_string_representation(comment)&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Verifies that the string representation of a &lt;code&gt;Comment&lt;/code&gt; object is correctly truncated to 20 characters.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rationale:&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input:&lt;/strong&gt; Uses the &lt;code&gt;comment&lt;/code&gt; fixture, which provides a &lt;code&gt;Comment&lt;/code&gt; with specific content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verification:&lt;/strong&gt; Checks that the output of &lt;code&gt;str(comment)&lt;/code&gt; matches the first 20 characters of the comment content (‘This is a test comment’).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; Ensures that the &lt;code&gt;___str___&lt;/code&gt; method of the &lt;code&gt;Comment&lt;/code&gt; model behaves correctly, truncating the content to 20 characters as expected, which is useful for displaying a preview of the comment in user interfaces.
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_comment_string_representation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Verify that the string representation of a Comment is correctly truncated to 20 characters.

    Args:
        comment: The Comment fixture providing a Comment object.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;strComment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This is a test comment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;strComment&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Testing repositories
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Files:&lt;/strong&gt;&lt;code&gt;test_repositories_comment.py&lt;/code&gt;, &lt;code&gt;test_repositories_post.py&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These tests will be in charge of ensuring that the repository methods work correctly both in normal conditions (when data exists) and in error situations (when data does not exist or there are database errors), thus ensuring the reliability of the repository code.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;test_repository_get_comment_by_id_exists(comment)&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Verify that a &lt;code&gt;Comment&lt;/code&gt; object can be retrieved by its ID when it exists in the database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Rationale:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt; Uses the comment fixture to provide an existing &lt;code&gt;Comment&lt;/code&gt; object.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Verification:&lt;/strong&gt; Uses the &lt;code&gt;get_comment_by_post_and_id&lt;/code&gt; method of the &lt;code&gt;CommentRepository&lt;/code&gt; to retrieve the comment by &lt;code&gt;post&lt;/code&gt; ID and &lt;code&gt;comment&lt;/code&gt; ID.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Asserts:&lt;/strong&gt; Checks that the retrieved &lt;code&gt;comment&lt;/code&gt; is equal to the &lt;code&gt;Comment&lt;/code&gt; object provided by the fixture.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Ensures that the repository method works correctly to retrieve existing comments, thus validating the basic functionality of the repository.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_repository_get_comment_by_id_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Verify that a Comment can be retrieved by its ID when it exists in the database.

    Args:
        comment: The Comment fixture providing a Comment object.

    Asserts:
        The result should be equal to the provided Comment object.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CommentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_comment_by_post_and_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;test_repository_get_comment_by_id_is_does_not_exist()&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Verify that trying to retrieve a &lt;code&gt;Comment&lt;/code&gt; by its ID when it does not exist returns &lt;code&gt;None&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Rationale:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt; Provides a &lt;code&gt;post&lt;/code&gt; ID and &lt;code&gt;comment&lt;/code&gt; ID that do not exist in the database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Verification:&lt;/strong&gt; Uses the &lt;code&gt;get_comment_by_post_and_id&lt;/code&gt; method of the &lt;code&gt;CommentRepository&lt;/code&gt; to try to retrieve the non-existent &lt;code&gt;comment&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Asserts:&lt;/strong&gt; Checks that the result is &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Ensures that the repository method correctly handles cases where the &lt;code&gt;comment&lt;/code&gt; does not exist, returning &lt;code&gt;None&lt;/code&gt; as expected.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@pytest.mark.django_db&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_repository_get_comment_by_id_is_does_not_exist&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Verify that attempting to retrieve a Comment by ID when it does not exist returns None.

    Asserts:
        The result should be None.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CommentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_comment_by_post_and_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;232&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9999&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Non-existent ID
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;(&lt;/p&gt;

&lt;p&gt;Little interlude so we know a bit more about what &lt;code&gt;@pytest.mark.django_db&lt;/code&gt; is and why we use it:&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;@pytest.mark.django_db&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; The &lt;code&gt;@pytest.mark.django_db&lt;/code&gt; decorator is used to indicate that the test interacts with the Django database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rationale:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input:&lt;/strong&gt; Some tests need to access or modify the database to verify correct code behaviour.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verification:&lt;/strong&gt; Without this decorator, tests that attempt to interact with the database would throw an error, as &lt;code&gt;pytest&lt;/code&gt; isolates tests from accessing the database by default to improve performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; This decorator is crucial for tests that verify the creation, update, delete or query of objects in the database, ensuring that database operations are performed in a controlled and isolated test environment.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;test_database_error_repository_create_comment(mocker)&lt;/code&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; To test whether the &lt;code&gt;create_comment&lt;/code&gt; repository method handles database errors (&lt;code&gt;DatabaseError&lt;/code&gt;) correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rationale:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input:&lt;/strong&gt; Uses mocker to patch the &lt;code&gt;Comment.objects.create&lt;/code&gt; method and simulate a &lt;code&gt;DatabaseError&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verification:&lt;/strong&gt; Attempts to create a comment using the &lt;code&gt;create_comment&lt;/code&gt; method of the &lt;code&gt;CommentRepository&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asserts:&lt;/strong&gt; Checks that a &lt;code&gt;DatabaseError&lt;/code&gt; is thrown as a result of the simulation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; Ensures that the repository handles database errors correctly during comment creation, thus validating the robustness and error handling capability of the repository.
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_database_error_repository_create_comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mocker&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Test if the repository method create_comment handles DatabaseError properly.

    Args:
        mocker: The pytest-mock fixture used to patch objects.

    Asserts:
        The method should raise a DatabaseError when a DatabaseError is simulated.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;mocker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;apps.comments.repositories.comment_repository.Comment.objects.create&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;side_effect&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DatabaseError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DatabaseError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;CommentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_comment&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;(&lt;/p&gt;

&lt;p&gt;Little interlude for us to learn a bit about what mocker is and how to use it:&lt;/p&gt;
&lt;h3&gt;
  
  
  Using &lt;code&gt;mocker&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt;&lt;code&gt;mocker&lt;/code&gt; is a tool provided by &lt;code&gt;pytest-mock&lt;/code&gt; that is used to patch methods or functions during testing. This allows to simulate different behaviours and situations of the components under test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rationale:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input:&lt;/strong&gt; In tests that verify database error handling, the &lt;code&gt;Comment.objects.create&lt;/code&gt; method is patched to simulate a &lt;code&gt;DatabaseError&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verification:&lt;/strong&gt; By patching this method, the desired behaviour (in this case, throwing a &lt;code&gt;DatabaseError&lt;/code&gt;) is forced without the need for the database to actually fail.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asserts:&lt;/strong&gt; Verifies that the code handles the simulated errors correctly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; The use of &lt;code&gt;mocker&lt;/code&gt; allows testing how the code handles exceptions and other specific cases without relying on unpredictable external conditions. It is a fundamental technique in unit testing to ensure that the code responds appropriately to different scenarios, including errors.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Testing REST API views
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Files:&lt;/strong&gt;&lt;code&gt;test_api_comment.py&lt;/code&gt;, &lt;code&gt;test_api_post.py&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These tests will ensure that the REST API views correctly handle the creation and updating of comments and posts, including input validation and error handling.&lt;/p&gt;

&lt;p&gt;This approach will help ensure that the REST API views are robust and handle different usage scenarios correctly, improving the quality and reliability of the code.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;test_create_comment(api_client, post)&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Verify that a new &lt;code&gt;Comment&lt;/code&gt; can be created for a &lt;code&gt;Post&lt;/code&gt; via the API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rationale:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input:&lt;/strong&gt; Uses the &lt;code&gt;api_client&lt;/code&gt; fixture to make API requests and the post fixture to provide a Post object.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action:&lt;/strong&gt; Makes a POST request to the &lt;code&gt;post-comment-create&lt;/code&gt; URL with the data needed to create a new comment.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Asserts:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verifies that the response status is &lt;code&gt;HTTP 201 Created&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Verifies that the response data includes the content of the new comment.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Ensures that the API handles the creation of new comments correctly by validating the resource creation functionality.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_create_comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Verify that a new Comment can be created for a Post via the API.

    Args:
        api_client: The APIClient fixture for making API requests.
        post: The Post fixture providing a Post object.

    Asserts:
        The response status should be HTTP 201 Created.
        The response data should include the content of the new Comment.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post-comment-create&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;New comment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_201_CREATED&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;New comment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;test_perform_update_raises_kwargs_does_not_exists()&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Verify that &lt;code&gt;perform_update&lt;/code&gt; throws an &lt;code&gt;APIException&lt;/code&gt; if &lt;code&gt;comment_pk&lt;/code&gt; is not present in &lt;code&gt;kwargs&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Rationale:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt; Creates an instance of &lt;code&gt;CommentRetrieveUpdateDestroyAPIView&lt;/code&gt; and sets &lt;code&gt;kwargs&lt;/code&gt; to an empty dictionary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Action:&lt;/strong&gt; Attempts to execute &lt;code&gt;perform_update&lt;/code&gt; without providing &lt;code&gt;comment_pk&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Asserts:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verifies that an &lt;code&gt;APIException&lt;/code&gt; is thrown.&lt;/li&gt;
&lt;li&gt;Verifies that the exception message is ‘Comment ID is required to update the comment.’&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Ensures that the view correctly handles cases where the required arguments are not present, providing proper validation and error handling.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_perform_update_raises_kwargs_does_not_exists&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Verify that perform_update raises an APIException if &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;comment_pk&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; is not provided in kwargs.

    Asserts:
        The exception message should be &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Comment ID is required to update the comment.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CommentRetrieveUpdateDestroyAPIView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perform_update&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;APIException&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Comment ID is required to update the comment.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;test_perform_update_invalid_comment_id()&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Verify that &lt;code&gt;perform_update&lt;/code&gt; throws an &lt;code&gt;APIException&lt;/code&gt; if &lt;code&gt;comment_pk&lt;/code&gt; has an invalid format.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rationale:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input:&lt;/strong&gt; Creates an instance of &lt;code&gt;CommentRetrieveUpdateDestroyAPIView&lt;/code&gt; and sets &lt;code&gt;kwargs&lt;/code&gt; with &lt;code&gt;comment_pk&lt;/code&gt; as an invalid value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action:&lt;/strong&gt; Uses a &lt;code&gt;MockSerializer&lt;/code&gt; to simulate a validated serializer and then attempts to execute perform_update.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Asserts:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verifies that an &lt;code&gt;APIException&lt;/code&gt; is thrown.&lt;/li&gt;
&lt;li&gt;Verifies that the exception message is ‘Invalid Comment ID format.’&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Ensures that the view correctly handles cases where arguments have an invalid format, thus validating the robustness of error handling and data validation.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MockSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Serializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Mock serializer class to simulate serializer behavior in tests.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;validated_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Test comment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_perform_update_invalid_comment_id&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Verify that perform_update raises an APIException if &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;comment_pk&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; has an invalid format.

    Asserts:
        The exception message should be &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid Comment ID format.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CommentRetrieveUpdateDestroyAPIView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comment_pk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;invalid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;serializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MockSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Test comment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# Simulate successful serializer validation
&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;APIException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;excinfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perform_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;excinfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid Comment ID format.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Testing web views
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Files:&lt;/strong&gt;&lt;code&gt;test_web_views_comment.py&lt;/code&gt;, &lt;code&gt;test_web_views_post.py&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These tests will verify that the ‘&lt;code&gt;Post&lt;/code&gt;’ and ‘&lt;code&gt;Comment’&lt;/code&gt; web views are working correctly. Helping to ensure that users can see the details and lists of ‘&lt;code&gt;Posts&lt;/code&gt;’ and ‘&lt;code&gt;Comments&lt;/code&gt;’ as expected in the web interface, improving the quality and reliability of the application.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;test_post_detail_view(client, post)&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Verify that the detail view of a &lt;code&gt;Post&lt;/code&gt; returns a successful response and that it includes the title of the specific &lt;code&gt;Post&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rationale:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;client:&lt;/strong&gt; Uses Django's &lt;code&gt;client&lt;/code&gt; fixture to make HTTP requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;post:&lt;/strong&gt; Use the &lt;code&gt;post&lt;/code&gt; fixture to provide a &lt;code&gt;Post&lt;/code&gt; object.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Action:&lt;/strong&gt; Make a GET request to the Post's detail URL using &lt;code&gt;reverse&lt;/code&gt; to resolve to the correct URL and pass the &lt;code&gt;Post&lt;/code&gt; ID.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Asserts:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verifies that the status of the response is &lt;code&gt;HTTP 200 OK&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Verifies that the content of the response includes the &lt;code&gt;Post&lt;/code&gt; title in binary format (&lt;code&gt;b ‘Test Post’&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; This test ensures that the &lt;code&gt;Post&lt;/code&gt; detail view works correctly and that the &lt;code&gt;Post&lt;/code&gt; title is displayed as expected, validating both functionality and data representation.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_post_detail_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Verify that the Post detail view returns a successful response and includes the title of the specific Post.

    Args:
        client: The Django test client fixture for making HTTP requests.
        post: The Post fixture providing a Post object.

    Asserts:
        The response status should be HTTP 200 OK.
        The response content should include the title of the Post.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post-detail&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Test Post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;test_comment_detail_view(client, comment)&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Purpose:** Verify that the detail view of a `Comment` returns a successful response and that it includes the content of the specific `Comment`.

    **Rationale:**

    * **Input:**

        * `client`**:** Uses Django's `client` fixture to make HTTP requests.

        * `comment`**:** Uses the `comment` fixture to provide a `Comment` object.

    * **Action:** Make a GET request to the Comment's detail URL using `reverse` to resolve to the correct URL and pass the `Post` and `Comment` IDs.

    * **Asserts:**

        * Verify that the status of the response is `HTTP 200 OK`.

        * Uses `BeautifulSoup` to parse the HTML content of the response and extract all elements.

        * Verifies that the content of the elements includes the text of the specific comment.

    * **Why:** This test ensures that the `Comment` detail view works correctly and that the `Comment` content is displayed as expected, validating both functionality and data representation.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```python
def test_comment_detail_view(client, comment):
    """
    Verify that the Comment detail view returns a successful response and includes the content of a specific Comment.

    Args:
        client: The Django test client fixture for making HTTP requests.
        comment: The Comment fixture providing a Comment object.

    Asserts:
        The response status should be HTTP 200 OK.
        The response content should include the text of the Comment.
    """
    response = client.get(
        reverse("post-comment-detail", args=[comment.post.id, comment.id])
    )
    assert response.status_code == 200

    soup = BeautifulSoup(response.content, "html.parser")
    comments = soup.find_all("p")
    comment_texts = [comment.get_text() for comment in comments]
    assert "This is a test comment" in comment_texts
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using Coverage with Pytest in our Django project
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Coverage&lt;/code&gt; is an essential tool for measuring test coverage in a project. It allows us to see which parts of the code are being tested and which are not, helping to identify areas that need more testing. In this section, we will look at two key commands for using &lt;code&gt;coverage&lt;/code&gt; in conjunction with &lt;code&gt;pytest&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Command 1:&lt;/strong&gt;&lt;code&gt;python -m coverage run -m pytest&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; coverage run &lt;span class="nt"&gt;-m&lt;/span&gt; pytest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;python -m coverage:&lt;/strong&gt; This command runs the &lt;code&gt;coverage&lt;/code&gt; module as a script. Using &lt;code&gt;-m&lt;/code&gt; instead of just &lt;code&gt;coverage&lt;/code&gt; ensures that the version of &lt;code&gt;coverage&lt;/code&gt; installed in the current virtual environment is used.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;run:&lt;/strong&gt; This subcommand of &lt;code&gt;coverage&lt;/code&gt; indicates that we want to run a script (in this case, &lt;code&gt;pytest&lt;/code&gt;) and measure the coverage while it is running.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;-m pytest:&lt;/strong&gt; This part of the command tells Python to execute the &lt;code&gt;pytest&lt;/code&gt; module. This way, &lt;code&gt;coverage&lt;/code&gt; will run &lt;code&gt;pytest&lt;/code&gt; and record code coverage during test execution.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This command runs all tests using &lt;code&gt;pytest&lt;/code&gt; and, at the same time, records the code coverage, generating a &lt;code&gt;.coverage&lt;/code&gt; file in the root directory of the project containing the coverage data.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Command 2:&lt;/strong&gt;&lt;code&gt;python -m coverage report --include=‘apps/’ --show-missing&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; coverage report &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"apps/*"&lt;/span&gt; &lt;span class="nt"&gt;--show-missing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;python -m coverage:&lt;/strong&gt; As in the previous command, executes the module &lt;code&gt;coverage&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;report:&lt;/strong&gt; This &lt;code&gt;coverage&lt;/code&gt; subcommand generates a coverage report on the terminal.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;--include=‘apps/*’:&lt;/strong&gt; This argument indicates that we only want to include files in the apps folder in the coverage report. You can adjust this path according to the structure of your projects and the scope you want to give to your test coverage. This is useful to exclude files you are not interested in, such as configuration files or third-party libraries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;--show-missing:&lt;/strong&gt; This argument adds a column to the report that shows which lines of each file were not covered by the tests. This makes it easier to identify specific areas of code that need further testing.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Running the tests with Coverage and Pytest
&lt;/h2&gt;
&lt;h3&gt;
  
  
  First command:
&lt;/h3&gt;

&lt;p&gt;The command &lt;code&gt;python -m coverage run -m&lt;/code&gt; pytest runs the tests using &lt;code&gt;pytest&lt;/code&gt; and also measures the coverage of the code.&lt;/p&gt;

&lt;p&gt;If you run the command, you should get something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvx6d0vcw7i5myp8aj9l6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvx6d0vcw7i5myp8aj9l6.png" alt="command 1" width="800" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Collection analysis and execution of tests:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Total tests collected:&lt;/strong&gt; 44.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Results:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All tests (44) passed successfully.&lt;/li&gt;
&lt;li&gt;The total execution time was 0.83s.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This result shows that all the tests that we defined so far in the project were executed correctly and passed. There were no failures, bugs or skipped tests, which indicates that the code under test behaves as expected in all cases covered by the tests.&lt;/p&gt;
&lt;h3&gt;
  
  
  Second command:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo2iebsb4gmei2qc5yy96.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo2iebsb4gmei2qc5yy96.png" alt="command 2" width="800" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Coverage Report Explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After running the command to generate the code coverage report, we will get a detailed breakdown of how the tests cover the source code as we can see in the image above.&lt;/p&gt;

&lt;p&gt;Let's take a closer look at what all this data means:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sections of the Report&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Name:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* This column shows the path to each file in the project that contains executable code.

* **For example**, `apps\comments\models.py` refers to the models.py file in the comments app.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Stmts:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* This column indicates the total number of statements (lines of executable code) in each file.

* **For example**, `apps\comments\models.py` has 9 statements.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Miss:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* This column shows how many statements in the file were not executed during testing.

* **For example**, if `apps\posts\views\web_views.py` has 4 lines not covered, it means that 4 lines of code in that file were not executed by the tests.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Cover:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* This column shows the percentage of coverage for each file. It represents the percentage of lines of code executed during testing.

* **For example**, `apps\posts\views\api_views.py` has a coverage of 71%, which means that 71% of its lines of code were executed during the tests.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Missing:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* This column lists the specific lines that were not covered by the tests.

* **For example**, `apps\comments\views\web_views.py` shows `21, 24-25, 54, 58, 60-63`, indicating that these lines were not executed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Meaning and Measurements&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Lines Not Covered (Miss):&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Meaning:** The lines of code listed in this column were not executed during testing. This could be because certain paths in the code are not being tested.

* **Action:** Add tests to cover these paths. For example, if there is error handling on these lines, make sure your tests include cases that trigger those errors.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Low Cover (Cover):&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Meaning:** A low percentage indicates that a large part of the code in that file is not being tested.

* **Action:** Review files with low coverage and add tests to cover more use cases. This may include additional unit tests or functional tests that exercise more code paths.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Full Coverage (100% Cover):&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Meaning:** All statements in these files were executed during testing.

* **Measurement:** Although the coverage is 100%, make sure that the tests also correctly verify the logic of the code, not just that it executes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Recommendations and Best Practices
&lt;/h2&gt;

&lt;p&gt;Finally, we will look at some recommendations, types of tests and best practices for effective application testing, especially in the context of applications such as this one.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Types of Tests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To achieve complete and effective coverage, consider implementing the following types of tests:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Unit Tests:** Verify the operation of individual pieces of code, such as functions, methods or classes. Make sure that each unit of code does what is expected without relying on other parts of the system.

* **Integration Tests:** Validate how different components of the system interact. In the Django REST Framework, this may include testing that API endpoints work correctly and that data is handled properly between views and models.

* **Functionality Testing:** This focuses on the full functionality of the system from the user's point of view. For example, make sure that users can create, read, update and delete resources correctly through the API.

* **Regression Testing:** Ensures that code changes do not break existing functionality. They should be run regularly to detect problems introduced by new features or bug fixes.

* **Performance Testing:** Verify the behaviour of the application under load and stress conditions. It is useful to identify bottlenecks and ensure that the application can handle the expected traffic.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Best Practices&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To ensure that your testing is effective and reliable, consider the following practices:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Code Coverage:** Although not a guarantee of quality, high code coverage (ideally over 80%) helps identify untested areas. Use tools such as `coverage.py` to measure and improve coverage.

* **Test Independence:** Each test should be independent and run in any order. Use fixtures to set the initial state and clean up after each test if necessary.

* **Use of Mocks and Stubs:** For unit tests, use mocks to simulate external behaviours and dependencies. This ensures that tests are fast and do not depend on external services or shared state.

* **Error and Exception Testing:** Be sure to test cases where the application must handle errors and exceptions. Verify that errors are handled properly and that useful messages are returned to the user.

* **Security Testing:** Include tests that verify the security of your application, such as permission validation and protection against common vulnerabilities (e.g., SQL injection, Cross-Site Scripting).

* **Testing in Real Environments:** Run your tests in environments that mimic the production environment as closely as possible to detect problems that only occur in specific configurations.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Additional Recommendations&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Keep Tests Readable and Maintainable:** Write tests that are clear and easy to understand. Use descriptive test names and keep test code clean and well organised.

* **Automate Test Execution:** Integrate your tests into the continuous integration (CI) process so that they run automatically on every code change. This helps identify problems quickly and ensures that new code does not break existing functionality.

* **Review and Refactor:** Regularly review and refactor your tests to improve their coverage and efficiency. Test code can also become obsolete over time, so keep it up to date.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And that's it for our basic guide to testing in a Django REST Framework project!&lt;/p&gt;

&lt;p&gt;Remember that testing is a crucial part of software development, and maintaining good coverage and well-defined tests will help you prevent bugs and improve the quality of your code over time.&lt;/p&gt;

&lt;p&gt;If you have additional questions, feel free to leave them in the comments.&lt;/p&gt;

&lt;p&gt;Thanks for reading and happy code testing!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Other topics you may be interested in:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/mateoramirezr" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1743449%2F4f728917-8640-49d2-954f-8bf7f5026fa1.png" alt="mateoramirezr"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mateoramirezr/how-to-name-endpoints-in-a-rest-api-complete-guide-with-best-practices-and-practical-example-1c3l" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;How to Name Endpoints in a REST API: Complete Guide with Best Practices and Practical Example&lt;/h2&gt;
      &lt;h3&gt;Mateo Ramirez Rubio ・ Jul 7&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#api&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#rest&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#backend&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



</description>
      <category>testing</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Complete Guide to the Django Services and Repositories Design Pattern with the Django REST Framework</title>
      <dc:creator>Mateo Ramirez Rubio</dc:creator>
      <pubDate>Mon, 08 Jul 2024 16:59:18 +0000</pubDate>
      <link>https://forem.com/mateoramirezr/complete-guide-to-the-django-services-and-repositories-design-pattern-with-the-django-rest-framework-37c7</link>
      <guid>https://forem.com/mateoramirezr/complete-guide-to-the-django-services-and-repositories-design-pattern-with-the-django-rest-framework-37c7</guid>
      <description>&lt;h2&gt;
  
  
  Introduction to the Django Services and Repositories Design Pattern with Django REST Framework
&lt;/h2&gt;

&lt;p&gt;In the world of software development, code organisation and maintainability are crucial to the long-term success of any project. In particular, when working with frameworks like Django and the Django REST Framework to build robust web applications and APIs, it's essential to follow design patterns that help us keep our code clean, modular and easy to scale.&lt;/p&gt;

&lt;p&gt;In this blog, we will explore one of these widely used design patterns: Services and Repositories. This pattern allows us to separate the concerns of data access and business logic, improving the structure and clarity of our code. Through this approach, we not only make our applications easier to maintain and test, but also more flexible and future-proof.&lt;/p&gt;

&lt;p&gt;Join us as we break down this pattern step-by-step, from initial project setup to service and repository deployment, and discover how it can transform the way you develop your Django apps.&lt;/p&gt;

&lt;p&gt;The realisation of the project is divided into three main sections: the structuring and design of the project; the coding of the structured project; testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can find the complete code and structure of the project in the following GitHub link:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/MateoRamirezRubio1" rel="noopener noreferrer"&gt;
        MateoRamirezRubio1
      &lt;/a&gt; / &lt;a href="https://github.com/MateoRamirezRubio1/mini-blog-rest-api" rel="noopener noreferrer"&gt;
        mini-blog-rest-api
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A mini blog Django project demonstrating the implementation of the Services and Repositories design pattern for a blog application.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;This project is a Django-based mini blog application designed to illustrate the implementation of the Services and Repositories design pattern. It features a clear separation of concerns, making the codebase easier to maintain and extend.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You can follow the step by step of the making of the app on my blog: &lt;a href="https://mateoramirezr.hashnode.dev/django-services-and-repositories-design-pattern-with-rest-api" rel="nofollow noopener noreferrer"&gt;My blog&lt;/a&gt;.&lt;/strong&gt;
&lt;br&gt;
&lt;strong&gt;You can see the application test here: &lt;a href="https://mateoramirezr.hashnode.dev/preview/669dcc8df7b0290261679dad" rel="nofollow noopener noreferrer"&gt;Testing App&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Posts and Comments:&lt;/strong&gt; Users can create, update, and delete blog posts and comments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RESTful API:&lt;/strong&gt; Provides endpoints for interacting with the application programmatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Interface:&lt;/strong&gt; Offers a basic user-friendly interface for managing posts and comments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service Layer:&lt;/strong&gt; Contains business logic and orchestrates interactions between views and repositories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository Layer:&lt;/strong&gt; Encapsulates data access logic, providing a clean API for the service layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Django Admin:&lt;/strong&gt; Allows administrative management of posts and comments.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Project Structure&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The project follows a modular structure, with each app having its own models…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/MateoRamirezRubio1/mini-blog-rest-api" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Also, now you can find the second part of this project where we do the testing of the complete app:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/mateoramirezr" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1743449%2F4f728917-8640-49d2-954f-8bf7f5026fa1.png" alt="mateoramirezr"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/mateoramirezr/mastering-testing-in-django-rest-framework-from-pytest-and-fixtures-to-mocks-and-coverage-4jg6" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Mastering Testing in Django REST Framework: From Pytest and Fixtures to Mocks and Coverage&lt;/h2&gt;
      &lt;h3&gt;Mateo Ramirez Rubio ・ Jul 22&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#testing&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#programming&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  Creation and design of the project
&lt;/h2&gt;

&lt;p&gt;In this first section, we will see how to create a new Django project with DRF (Django REST Framework) and we will analyse how the main parts of the project and REST APIs will be structured.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;h3&gt;
  
  
  Start and creation of the Django project
&lt;/h3&gt;

&lt;p&gt;Before starting the project, you must install Django and Django REST Framework if you don't already have it:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;django djangorestframework
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Now that we've installed the main tools we're going to use for the project, we'll create a new Django project using the &lt;code&gt;django-admin startproject&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;django-admin startproject my_project_blog
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This command generates the basic structure of a Django project, including configuration files and a project directory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3&gt;
  
  
  Creation of Django applications
&lt;/h3&gt;

&lt;p&gt;For this small blog project, we will have two main functionalities which we will divide into two Django apps: &lt;code&gt;Posts&lt;/code&gt; and &lt;code&gt;Comments&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For this, in the terminal, inside the main project directory (my_project_blog), create two applications: &lt;code&gt;Posts&lt;/code&gt; and &lt;code&gt;Comments&lt;/code&gt; using the python command &lt;code&gt;manage.py startapp&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py startapp posts
python manage.py startapp comments
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Apps are modular Django components that group related functionalities. In this case, &lt;code&gt;Posts&lt;/code&gt; will handle blog posts and &lt;code&gt;Comments&lt;/code&gt; will handle comments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;h3&gt;
  
  
  &lt;strong&gt;File settings:&lt;/strong&gt;
&lt;/h3&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Add the created apps and the DRF to the &lt;code&gt;INSTALLED_APPS&lt;/code&gt; section in the project settings file: &lt;code&gt;/my_project_blog/my_project_blog/settings.py&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rest_framework&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apps.posts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apps.comments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;### Project structure:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next I will show you how the project will be structured, you can create all the directories/folders and files (ignore &lt;code&gt;README.md&lt;/code&gt;, &lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;.gitignore&lt;/code&gt;), and then we will fill them with code as we learn.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Main structure:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzix4lbbyexs80tg57xoh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzix4lbbyexs80tg57xoh.png" alt="Main structure Image" width="170" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Structure of the Comments app:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firebacb1qw9q9gfswbc4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firebacb1qw9q9gfswbc4.png" alt="Structure of the Comments app Image" width="205" height="693"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Structure of the Posts app:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhzkzv5mly9p8ug6erif.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhzkzv5mly9p8ug6erif.png" alt="Structure of the Posts app Image" width="182" height="769"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;### System design:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the realisation of the project we opted for an architecture based on layers and classic design patterns such as Repository and Services.&lt;/p&gt;

&lt;p&gt;The Services and Repositories pattern divides business logic (services) and data access logic (repositories) into separate layers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Web Layer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;It presents the data to users. In this case, the views are for both REST APIs (using DRF) and web views (using Django Views). &lt;strong&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/strong&gt; REST APIs views handle all the API logic (CRUD, etc), while web views only handle sending data to the user via templates.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Service layer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Contains the business logic. It communicates with the &lt;code&gt;Repository Layer&lt;/code&gt; to retrieve data and performs additional operations (without interacting directly with the database) before returning data to the views or controllers.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Repository Layer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;It is responsible for interacting directly with the database. This layer is responsible for basic CRUD operations. &lt;strong&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/strong&gt; This layer is the only one in charge of interacting directly with the database.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Model Layer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data models representing the database tables.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fic2bnd902divq7h31yt3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fic2bnd902divq7h31yt3.png" alt="Arquitecture Pattern" width="761" height="1159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will delve a little deeper into each layer later as we code.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;### Design of REST APIs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;REST APIs allow communication between the frontend and the backend. We use the Django REST Framework to create RESTful APIs. This is the structure we have for their respective naming and functions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;HTTP Method&lt;/th&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GET&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/posts/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gets a list of all posts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;POST&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/posts/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a new post in the database.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GET&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/posts/{post_id}/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gets the details of a specific post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PUT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/posts/{post_id}/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update a specific post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DELETE&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/posts/{post_id}/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete a specific post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GET&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/posts/{post_id}/comments/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gets a list of comments for a post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;POST&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/posts/{post_id}/comments/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a new comment for a post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GET&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/posts/{post_id}/comments/{comment_id}/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gets the details of a comment on a post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PUT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/posts/{post_id}/comments/{comment_id}/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update a comment on a post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DELETE&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/posts/{post_id}/comments/{comment_id}/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove a comment from a post.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Coding and deepening
&lt;/h2&gt;

&lt;p&gt;Now that we are clear about the layout of the project, for the second section, we will code our blogging project by delving into several of the layers we talked about earlier.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;h3&gt;
  
  
  Model:
&lt;/h3&gt;

&lt;p&gt;The Model represents the data. It defines the database tables. In Django, models are classes that inherit from &lt;code&gt;models.Model&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For this project we will create two models, one for each Django app:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Modelo&lt;/th&gt;
&lt;th&gt;Fields&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Post&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'title', 'content'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;It represents a blog post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Comment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'post', 'content'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Represents a comment associated with a post.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the archive:&lt;/strong&gt;&lt;code&gt;/my_project_blog/apps/posts/models.py&lt;/code&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DateTimeField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto_now_add&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DateTimeField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto_now&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__str__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the archive:&lt;/strong&gt;&lt;code&gt;/my_project_blog/apps/comments/models.py&lt;/code&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;apps.posts.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;related_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;on_delete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DateTimeField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto_now_add&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DateTimeField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto_now&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__str__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;### Views&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The View handles user requests and returns responses. Django offers both class-based views (CBV) and function-based views (FBV).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CommentListView&lt;/code&gt; and &lt;code&gt;CommentDetailView&lt;/code&gt; are examples of Class-Based Views (CBV).&lt;/p&gt;

&lt;p&gt;Separation of concerns is a design principle that promotes the separation of a program into distinct sections, with each section addressing a separate concern.&lt;/p&gt;

&lt;p&gt;As we saw earlier for this project, we separated the views into two:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;API REST Views:&lt;/strong&gt; Handle API-specific logic, such as serialisation, validation and returning JSON responses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Traditional Django Views (Web Views):&lt;/strong&gt; They handle rendering templates, session management and other web-specific logic.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For the Posts app:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the archive:&lt;/strong&gt;&lt;code&gt;/my_project_blog/apps/posts/views/api_views.py&lt;/code&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rest_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;generics&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..serializers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PostSerializer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..services.post_service&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PostService&lt;/span&gt;

&lt;span class="c1"&gt;# API view for listing all posts and creating a new post.
# Utilizes Django REST Framework's ListCreateAPIView for listing and creating resources.
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostListCreateAPIView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListCreateAPIView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;serializer_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PostSerializer&lt;/span&gt;  &lt;span class="c1"&gt;# Defines the serializer class used for converting model instances to JSON and vice versa.
&lt;/span&gt;
    &lt;span class="c1"&gt;# Fetches all posts from the database.
&lt;/span&gt;    &lt;span class="c1"&gt;# `get_queryset` method specifies the queryset for listing posts.
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_queryset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;PostService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_all_posts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Delegates the database query to the PostService layer.
&lt;/span&gt;
    &lt;span class="c1"&gt;# Handles the creation of a new post.
&lt;/span&gt;    &lt;span class="c1"&gt;# `perform_create` is called after validation of the serializer.
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;perform_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Creates a new post using validated data from the serializer.
&lt;/span&gt;        &lt;span class="n"&gt;PostService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validated_data&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Uses PostService to handle creation logic.
&lt;/span&gt;
&lt;span class="c1"&gt;# API view for retrieving, updating, and deleting a specific post.
# Extends RetrieveUpdateDestroyAPIView for detailed operations on a single resource.
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostRetrieveUpdateDestroyAPIView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RetrieveUpdateDestroyAPIView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;serializer_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PostSerializer&lt;/span&gt;  &lt;span class="c1"&gt;# Specifies the serializer class for retrieving, updating, and deleting resources.
&lt;/span&gt;
    &lt;span class="c1"&gt;# Retrieves a post object based on the provided post_id.
&lt;/span&gt;    &lt;span class="c1"&gt;# `get_object` method returns the post instance for the specified post_id.
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Extracts post_id from the URL kwargs.
&lt;/span&gt;        &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PostService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_post_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;post_id&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Fetches the post using PostService.
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Comment not fund&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Raises a 404 error if the post does not exist.
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;  &lt;span class="c1"&gt;# Returns the post instance.
&lt;/span&gt;
    &lt;span class="c1"&gt;# Updates an existing post instance.
&lt;/span&gt;    &lt;span class="c1"&gt;# `perform_update` is called after the serializer's data is validated.
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;perform_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Extracts post_id from the URL kwargs.
&lt;/span&gt;        &lt;span class="c1"&gt;# Updates the post with new data.
&lt;/span&gt;        &lt;span class="n"&gt;PostService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validated_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Delegates the update logic to PostService.
&lt;/span&gt;
    &lt;span class="c1"&gt;# Deletes a post instance.
&lt;/span&gt;    &lt;span class="c1"&gt;# `perform_destroy` is called to delete the specified post.
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;perform_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Extracts post_id from the URL kwargs.
&lt;/span&gt;        &lt;span class="c1"&gt;# Deletes the post using PostService.
&lt;/span&gt;        &lt;span class="n"&gt;PostService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Delegates the deletion logic to PostService.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the archive:&lt;/strong&gt;&lt;code&gt;/my_project_blog/apps/posts/views/web_views.py&lt;/code&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.views.generic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ListView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DetailView&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..services.post_service&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PostService&lt;/span&gt;

&lt;span class="c1"&gt;# Class-based view for listing all posts in the web interface.
# Utilizes Django's ListView to handle displaying a list of posts.
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostListView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ListView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;  &lt;span class="c1"&gt;# Specifies the model to be used in the view.
&lt;/span&gt;    &lt;span class="n"&gt;template_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;posts/post_list.html&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# Path to the template for rendering the list of posts.
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;context_object_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;posts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# Context variable name to be used in the template.
&lt;/span&gt;
    &lt;span class="c1"&gt;# Overrides the default get_queryset method to fetch all posts from the service layer.
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_queryset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;PostService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_all_posts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Delegates the database query to the PostService.
&lt;/span&gt;
&lt;span class="c1"&gt;# Class-based view for displaying the details of a single post.
# Utilizes Django's DetailView to handle displaying detailed information of a single post.
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostDetailView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DetailView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;
    &lt;span class="n"&gt;template_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;posts/post_detail.html&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;context_object_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# Overrides the default get_object method to fetch a specific post based on post_id.
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;queryset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Extracts post_id from the URL kwargs.
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PostService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_post_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;post_id&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Fetches the post using the PostService.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;For the Comments app:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the archive:&lt;/strong&gt;&lt;code&gt;/my_project_blog/apps/comments/views/api_views.py&lt;/code&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rest_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;generics&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..serializers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CommentSerializer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..services.comment_service&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CommentService&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rest_framework.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;NotFound&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CommentListCreateAPIView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListCreateAPIView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;serializer_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CommentSerializer&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_queryset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Retrieve the 'post_id' from the URL kwargs. This ID is used to filter comments related to a specific post.
&lt;/span&gt;        &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Fetch comments related to the given post ID using the CommentService. The repository layer handles actual data fetching.
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CommentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_comments_by_post_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;perform_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Retrieve the 'post_id' from the URL kwargs. This ID is used to associate the new comment with a specific post.
&lt;/span&gt;        &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Create a new comment for the specified post using the CommentService. The service layer handles data manipulation.
&lt;/span&gt;        &lt;span class="n"&gt;CommentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validated_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CommentRetrieveUpdateDestroyAPIView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RetrieveUpdateDestroyAPIView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;serializer_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CommentSerializer&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Retrieve the 'post_id' and 'comment_pk' from the URL kwargs.
&lt;/span&gt;        &lt;span class="c1"&gt;# 'post_id' is used to ensure the comment belongs to the post, while 'comment_pk' identifies the specific comment.
&lt;/span&gt;        &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;comment_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comment_pk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Fetch the specific comment for the given post ID and comment ID using the CommentService.
&lt;/span&gt;        &lt;span class="c1"&gt;# Raise a 404 error if the comment is not found.
&lt;/span&gt;        &lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CommentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_comment_by_post_and_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Comment not fund&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;perform_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Retrieve the 'comment_pk' from the URL kwargs for updating the specific comment.
&lt;/span&gt;        &lt;span class="n"&gt;comment_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comment_pk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="c1"&gt;# Update the specified comment using the CommentService. The service layer handles data manipulation.
&lt;/span&gt;        &lt;span class="n"&gt;CommentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validated_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;perform_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Retrieve the 'comment_pk' from the URL kwargs for deleting the specific comment.
&lt;/span&gt;        &lt;span class="n"&gt;comment_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comment_pk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="c1"&gt;# Delete the specified comment using the CommentService. The service layer handles data manipulation.
&lt;/span&gt;        &lt;span class="n"&gt;CommentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete_comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the archive:&lt;/strong&gt;&lt;code&gt;/my_project_blog/apps/comments/views/api_views.py&lt;/code&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.views.generic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ListView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DetailView&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Comment&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..services.comment_service&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CommentService&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CommentListView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ListView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Comment&lt;/span&gt;
    &lt;span class="n"&gt;template_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comments/comment_list.html&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;context_object_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_queryset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Extract 'post_id' from URL parameters to fetch comments associated with a specific post.
&lt;/span&gt;        &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Use the CommentService to retrieve comments for the specified post.
&lt;/span&gt;        &lt;span class="c1"&gt;# The service layer handles data access logic, keeping the view simple.
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CommentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_comments_by_post_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_context_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Get the default context from the parent class and add additional context for 'post_id'.
&lt;/span&gt;        &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get_context_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Include 'post_id' in the context so it can be used in the template.
&lt;/span&gt;        &lt;span class="c1"&gt;# This is necessary for rendering links or forms related to the post.
&lt;/span&gt;        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CommentDetailView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DetailView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Comment&lt;/span&gt;
    &lt;span class="n"&gt;template_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comments/comment_detail.html&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;context_object_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;queryset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Extract 'post_id' and 'comment_id' from URL parameters to retrieve a specific comment for a post.
&lt;/span&gt;        &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;comment_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comment_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Use the CommentService to retrieve the specific comment based on 'post_id' and 'comment_id'.
&lt;/span&gt;        &lt;span class="c1"&gt;# If the comment is not found, `CommentService.get_comment_by_post_and_id` will return None.
&lt;/span&gt;        &lt;span class="c1"&gt;# In this case, a 404 error will be raised automatically by the `DetailView` if the object is not found.
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CommentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_comment_by_post_and_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;### Repositories&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Repositories handle data persistence and encapsulate data access logic. They are defined in separate files (&lt;code&gt;repositories.py&lt;/code&gt;) within each application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For the Post app:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the archive:&lt;/strong&gt;&lt;code&gt;/my_project_blog/apps/posts/repositories/post_repository.py&lt;/code&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Fetch all posts from the database
&lt;/span&gt;    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_all_posts&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Fetch a specific post by its primary key (ID)
&lt;/span&gt;    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_post_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Create a new post with the provided data
&lt;/span&gt;    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Update an existing post with the provided data
&lt;/span&gt;    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="nf"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Dynamically update each attribute
&lt;/span&gt;        &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;

    &lt;span class="c1"&gt;# Delete a post by its primary key (ID)
&lt;/span&gt;    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delete_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;For the Comments app:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the archive:&lt;/strong&gt;&lt;code&gt;/my_project_blog/apps/comments/repositories/comment_repository.py&lt;/code&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Comment&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CommentRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_comments_by_post_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Retrieve all comments associated with a specific post_id
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_comment_by_post_and_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Retrieve a specific comment by post_id and comment_id
&lt;/span&gt;        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DoesNotExist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Return None if no comment is found
&lt;/span&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Create a new comment associated with a specific post_id
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Update an existing comment identified by comment_id
&lt;/span&gt;        &lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="nf"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delete_comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Delete an existing comment identified by comment_id
&lt;/span&gt;        &lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;### Services&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Services contain the business logic and act as intermediaries between views and repositories. They are defined in separate files (&lt;code&gt;services.py&lt;/code&gt;) within each application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For the Post app:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the archive:&lt;/strong&gt;&lt;code&gt;/my_project_blog/apps/posts/services/post_service.py&lt;/code&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..repositories.post_repository&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PostRepository&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_all_posts&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="c1"&gt;# Retrieve all posts from the repository
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PostRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_all_posts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_post_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Retrieve a post by its ID from the repository
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PostRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_post_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Create a new post with the given data
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PostRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Update an existing post with the given data
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PostRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delete_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Delete a post by its ID from the repository
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PostRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;For the Comments app:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the archive:&lt;/strong&gt;&lt;code&gt;/my_project_blog/apps/comments/services/comment_service.py&lt;/code&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..repositories.comment_repository&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CommentRepository&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CommentService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_comments_by_post_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Delegate the task of retrieving comments by post_id to the repository layer
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CommentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_comments_by_post_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_comment_by_post_and_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Delegate the task of retrieving a specific comment by post_id and comment_id to the repository layer
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CommentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_comment_by_post_and_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Delegate the task of creating a new comment to the repository layer
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CommentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Delegate the task of updating an existing comment to the repository layer
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CommentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delete_comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Delegate the task of deleting a comment to the repository layer
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CommentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete_comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;### Serializers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Serializers convert complex data into native data formats (JSON) and vice versa. Serialisers are an important part of creating REST APIs with DRF which are not usually used in a normal Django project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For the Post app:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the archive:&lt;/strong&gt;&lt;code&gt;/my_project_blog/apps/posts/serializers.py&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rest_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;

&lt;span class="c1"&gt;# Serializer for the Post model
# This class is responsible for converting Post instances into JSON data and validating incoming data for creating or updating posts.
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="c1"&gt;# Meta class specifies the model and fields to be used by the serializer.
&lt;/span&gt;    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;  &lt;span class="c1"&gt;# The model associated with this serializer. It tells DRF which model the serializer will be handling.
&lt;/span&gt;        &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__all__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# Specifies that all fields from the model should be included in the serialization and deserialization process.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;For the Comments app:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the archive:&lt;/strong&gt;&lt;code&gt;/my_project_blog/apps/comments/serializers.py&lt;/code&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rest_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Comment&lt;/span&gt;

&lt;span class="c1"&gt;# CommentSerializer is a ModelSerializer that automatically creates fields and methods for the Comment model.
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CommentSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Comment&lt;/span&gt;  &lt;span class="c1"&gt;# The model that this serializer will be based on.
&lt;/span&gt;        &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__all__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# Automatically include all fields from the Comment model.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;### Configuration of URLs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;URLs are organised into two separate files for the API and web views, allowing a clear separation between accessing data via the API and presenting data via web views. This organisation facilitates code management and maintenance by distinguishing between paths that serve JSON data and paths that present HTML views.&lt;/p&gt;

&lt;p&gt;API routes are defined only in the &lt;code&gt;Posts&lt;/code&gt; application to centralise the management of resources related to posts and their comments. By not having its own &lt;code&gt;urls.py&lt;/code&gt; file in the &lt;code&gt;Comments&lt;/code&gt; application, redundancy is reduced and the project structure is simplified by grouping all related API paths in one place. This makes it easier to understand the data flow and the interrelationship between posts and comments, promoting a more coherent and maintainable architecture, and the correct use of REST best practices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;URLs API REST:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the archive:&lt;/strong&gt;&lt;code&gt;/my_project_blog/apps/posts/urls/api_urls.py&lt;/code&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.urls&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..views.api_views&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PostListCreateAPIView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PostRetrieveUpdateDestroyAPIView&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;...comments.views.api_views&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;CommentListCreateAPIView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;CommentRetrieveUpdateDestroyAPIView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# Route for listing all posts or creating a new post
&lt;/span&gt;    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PostListCreateAPIView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post-list-create&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;# Route for retrieving, updating, or deleting a specific post by post_id
&lt;/span&gt;    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;int:post_id&amp;gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;PostRetrieveUpdateDestroyAPIView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post-retrieve-update-destroy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;# Route for listing all comments for a specific post or creating a new comment for that post
&lt;/span&gt;    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;int:post_id&amp;gt;/comments/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;CommentListCreateAPIView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post-comment-create&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;# Route for retrieving, updating, or deleting a specific comment by comment_pk for a specific post
&lt;/span&gt;    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;int:post_id&amp;gt;/comments/&amp;lt;int:comment_pk&amp;gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;CommentRetrieveUpdateDestroyAPIView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post-comment-retrieve-update-destroy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;URLs web:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the archive:&lt;/strong&gt;&lt;code&gt;/my_project_blog/apps/posts/urls/web_urls.py&lt;/code&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.urls&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..views.web_views&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PostListView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PostDetailView&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;...comments.views.web_views&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CommentListView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CommentDetailView&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# Route for listing all posts.
&lt;/span&gt;    &lt;span class="c1"&gt;# The URL is "web/posts/", and it maps to PostListView to display a list of all posts.
&lt;/span&gt;    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PostListView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post-list&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;# Route for displaying details of a specific post identified by post_id.
&lt;/span&gt;    &lt;span class="c1"&gt;# The URL is "web/posts/&amp;lt;post_id&amp;gt;/", and it maps to PostDetailView to display details of a single post.
&lt;/span&gt;    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;int:post_id&amp;gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PostDetailView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post-detail&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;# Route for listing all comments for a specific post identified by post_id.
&lt;/span&gt;    &lt;span class="c1"&gt;# The URL is "web/posts/&amp;lt;post_id&amp;gt;/comments", and it maps to CommentListView to display a list of comments for the given post.
&lt;/span&gt;    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;int:post_id&amp;gt;/comments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;CommentListView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post-comments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;# Route for displaying details of a specific comment identified by comment_id for a specific post.
&lt;/span&gt;    &lt;span class="c1"&gt;# The URL is "web/posts/&amp;lt;post_id&amp;gt;/comments/&amp;lt;comment_id&amp;gt;/", and it maps to CommentDetailView to display details of a single comment.
&lt;/span&gt;    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;int:post_id&amp;gt;/comments/&amp;lt;int:comment_id&amp;gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;CommentDetailView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post-comment-detail&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;General project URLs:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the archive:&lt;/strong&gt;&lt;code&gt;/my_project_blog/my_project_blog/urls.py&lt;/code&gt; :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.contrib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.urls&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;admin/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;posts/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apps.posts.urls.web_urls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api/posts/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apps.posts.urls.api_urls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Web application and API testing
&lt;/h2&gt;

&lt;p&gt;Now, in the third section of this blog, we will create some posts and add several comments to each of the posts to verify the correct functioning of the web application and the API and web URLs.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;h3&gt;
  
  
  Execute the project
&lt;/h3&gt;

&lt;p&gt;- &lt;strong&gt;Creates Migrations:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py makemigrations
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;- &lt;strong&gt;Apply migrations:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py migrate
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;- &lt;strong&gt;Run the Django development server:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py runserver
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/strong&gt; Open your browser and navigate to &lt;code&gt;http://127.0.0.1:8000/&lt;/code&gt;, from now on the urls that I will give you will be after the domain (in this case our &lt;code&gt;localhost&lt;/code&gt;), example: If I give you the url &lt;code&gt;/api/posts/&lt;/code&gt;, in the browser you will have to put &lt;code&gt;http://127.0.0.1:8000/api/posts/&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Creation of posts&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Access the Django REST API interface:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **URL:**`/api/posts/`

* **Action:** Fill in the form with the details of the post to be created and click on the "POST" button.
&lt;/code&gt;&lt;/pre&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl0v9rwhcrmjn7k2s6gki.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl0v9rwhcrmjn7k2s6gki.png" alt="api posts image" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Add comments to posts:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Access the Django REST API interface:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **URL:**`/api/posts/{post_id}/comments/`

* **Action:** Fill in the form with the details of the comment to be created for a specific post and click on the "POST" button.
&lt;/code&gt;&lt;/pre&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6gqhowi38zuf5xwosva4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6gqhowi38zuf5xwosva4.png" alt="api comments image" width="800" height="627"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You can repeat these steps to create as many posts and comments as you want.

Also, in this same Django REST API interface you can edit posts or comments or delete them.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;### Verify the creation of posts and comments:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Having already created several posts and comments for some of these via the REST API, we can see these in the web URLs that interact with the HTML templates.&lt;/p&gt;

&lt;p&gt;So that when you enter the given URLs you can see the same design, you can see the HTML code of each template in the HTML files of the project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/MateoRamirezRubio1/mini-blog-rest-api" rel="noopener noreferrer"&gt;&lt;strong&gt;Full project code on GitHub&lt;/strong&gt;&lt;/a&gt;: &lt;a href="https://github.com/MateoRamirezRubio1/mini-blog-rest-api" rel="noopener noreferrer"&gt;&lt;em&gt;Click&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;See the list of posts:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **URL:**`/posts/`
&lt;/code&gt;&lt;/pre&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyktt5nnper0mip5aifmq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyktt5nnper0mip5aifmq.png" alt="posts list image" width="763" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2. **See the details of a specific post:**

    * **URL:**`/posts/{post_id}/`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpeocz2ej5fwtrga8830i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpeocz2ej5fwtrga8830i.png" alt="details post image" width="763" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3. **See comments on a specific post:**

    * **URL:**`/posts/{post_id}/comments/`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbwanjg9wsywmrlndwbe5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbwanjg9wsywmrlndwbe5.png" alt="comments post image" width="766" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4. **View the details of a comment on a specific post:**

    * **URL:**`/posts/{post_id}/comments/{comment_id}/`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fszguhyzhtlh0kmmic1m5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fszguhyzhtlh0kmmic1m5.png" alt="detail comments image" width="765" height="205"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Benefits of the Services and Repositories Employer
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Separation of Responsibilities:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Separation of responsibilities is one of the fundamental principles in software design. In the &lt;code&gt;Services&lt;/code&gt; and &lt;code&gt;Repositories&lt;/code&gt; pattern, we clearly separate data access concerns (repositories) from business logic (services).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Clarity and Organisation:** The code is organised so that each class and function has a single, clearly defined responsibility. This makes the code easier to understand and maintain.

* **Maintainability:** When the business logic changes, only the services need to be modified, while the repositories remain unchanged. This reduces the number of changes and the risk of introducing errors.

* **Team Collaboration:** In a development team, different members can work at different layers (e.g. one on services and one on repositories) without interfering with each other, facilitating collaboration and integration.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Re-use of the Code:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The pattern encourages code reuse by centralising business logic and data access in specific classes. This avoids code duplication and facilitates code reuse in different parts of the application.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Duplication Reduction:** By having business logic in services and data access in repositories, we avoid repeating code in multiple places, making the code more DRY (Don't Repeat Yourself).

* **Consistency:** Reusing the same code in different parts of the application ensures that the same logic and rules are followed everywhere, which increases consistency and reduces errors.

* **Ease of Update:** If you need to change the way data is accessed or business logic is implemented, you only need to update the corresponding repository or service. The other parts of the application that depend on them will automatically benefit from the changes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ease of Testing:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The separation of business logic and data access logic facilitates the creation of unit and integration tests. Services and repositories can be tested in isolation, which simplifies the testing process.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Unit testing:** By having business logic in services and data access in repositories, it is easier to create unit tests for each component independently. This makes it possible to quickly detect errors and ensure that each part works correctly.

* **Mocks and Stubs:** During testing, it is easy to use mocks and stubs to simulate the behaviour of repositories or services. This allows testing business logic without relying on the database or other external services.

* **Reduced Testing Complexity:** By having clear and well-defined responsibilities, testing becomes less complex and more specific. This improves test coverage and software reliability.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Maintainability and Extensibility:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Services&lt;/code&gt; and &lt;code&gt;Repositories&lt;/code&gt; pattern makes code more maintainable and extensible. This is especially important in long-term projects, where requirements may change over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Code Evolution:** When you need to add new functionality, it is easy to extend existing services and repositories without affecting the rest of the application. This allows the code to evolve in a controlled and safe way.

* **Easy Refactoring:** If you identify an improvement in the code structure or business logic implementation, it is easy to refactor services and repositories without great risk. The separation of responsibilities makes it easy to identify which parts of the code need to be changed.

* **Adaptability to New Technologies:** If at some point you decide to change the persistence technology (for example, from a SQL database to a NoSQL one), you only need to modify the repositories without affecting the business logic implemented in the services.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;Finally, in closing, I thank you for your time and attention in following this guide to the Services and Repositories design pattern in a Django project with the Django REST Framework. I hope this detailed explanation has given you a solid understanding of how to structure your applications in an efficient and maintainable way.&lt;/p&gt;

&lt;p&gt;Implementing this pattern will not only improve the organization of your code, but also facilitate its evolution and scalability as your project grows. If you have any additional questions or opinions on the topic, feel free to post in the comments, they are left open for discussion.&lt;/p&gt;

&lt;p&gt;Good luck with your development and best of luck with your future projects!&lt;/p&gt;

&lt;p&gt;See you next time!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>django</category>
      <category>backend</category>
      <category>api</category>
    </item>
    <item>
      <title>How to Name Endpoints in a REST API: Complete Guide with Best Practices and Practical Example</title>
      <dc:creator>Mateo Ramirez Rubio</dc:creator>
      <pubDate>Sun, 07 Jul 2024 18:57:46 +0000</pubDate>
      <link>https://forem.com/mateoramirezr/how-to-name-endpoints-in-a-rest-api-complete-guide-with-best-practices-and-practical-example-1c3l</link>
      <guid>https://forem.com/mateoramirezr/how-to-name-endpoints-in-a-rest-api-complete-guide-with-best-practices-and-practical-example-1c3l</guid>
      <description>&lt;h2&gt;
  
  
  Introduction:
&lt;/h2&gt;

&lt;p&gt;Naming the endpoints of a REST API may seem like a simple task, but in reality, it is one of the keys to ensuring that your API is intuitive, easy to use and maintain. Imagine trying to navigate a system where the paths don't make sense or don't follow a logical pattern. It would be like trying to find your way in a city with no road signs. In this blog, we'll look at some best practices for naming your endpoints effectively, ensuring that your users and developers can interact with your API clearly and efficiently. At the end, you'll see a complete example that you can use as a practical exercise to apply what you've learned - read on to master the art of naming endpoints in REST APIs!&lt;/p&gt;




&lt;h2&gt;
  
  
  Contents:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Introduction.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Recommendations for naming your endpoints.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Represent resources and not actions.&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Nested hierarchical structure.&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Use of clear and descriptive names.&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Consistency in the use of upper and lower case letters.&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Avoid file extensions.&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Endpoint naming formula.&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Complete REST API endpoint naming design example.&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Acknowledgments.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;

&lt;/ol&gt;




&lt;h2&gt;
  
  
  Recommendations for naming your endpoints
&lt;/h2&gt;

&lt;p&gt;When we design a REST API, we want it to be easy to understand and use. To achieve this we must follow some rules to name our URLs in a consistent way.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;h2&gt;
  
  
  Represent resources and not actions (&lt;em&gt;resources should be named in plural&lt;/em&gt;):
&lt;/h2&gt;

&lt;p&gt;You can fall into the trap of using actions or verbs when naming your endpoints such as:&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;del&gt;&lt;em&gt;How not to do it:&lt;/em&gt;&lt;/del&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /deleteBook/321&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /deleteBook?id=321&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POST /books/321/delete&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;p&gt;Following the REST parameters, this is not well done, the correct way to do it for this example is that there is a resource called Books and through the HTTP methods we say the action we want to do as for example delete it (DELETE) like this:&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;How to do it right:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DELETE /books/321&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2&gt;
  
  
  Nested hierarchical structure:
&lt;/h2&gt;

&lt;p&gt;To maintain good consistency and coherence in our URLs, we must use a hierarchical structure that shows relationships between resources. Example:&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;del&gt;&lt;em&gt;How not to do it:&lt;/em&gt;&lt;/del&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/books?libraryId=123&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/comments?bookId=456&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;How to do it right:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/libraries/123/books&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/books/456/comments&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2&gt;
  
  
  Use of clear and descriptive names:
&lt;/h2&gt;

&lt;p&gt;Continuing with consistency in the naming of endpoints and knowing that verbs should not be used to name resources, remember to use names that clearly describe the resources.&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;del&gt;&lt;em&gt;How not to do it:&lt;/em&gt;&lt;/del&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/data&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/info&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;How to do it right:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/users&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/products&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2&gt;
  
  
  Consistency in the use of upper and lower case letters:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;del&gt;&lt;em&gt;How not to do it:&lt;/em&gt;&lt;/del&gt;&lt;/strong&gt; Mixing upper and lower case inconsistently:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/UserProfiles&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/Order_Details&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to do it right:&lt;/strong&gt; Use lowercase letters and hyphens consistently:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/user-profiles&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/order-details&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h2&gt;
  
  
  Avoid file extensions:
&lt;/h2&gt;

&lt;p&gt;It may seem very obvious, but let's not overlook the fact that we should not use file extensions in the resource name in our URL, we should let the content type be determined by the HTTP headers.&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;del&gt;&lt;em&gt;How not to do it:&lt;/em&gt;&lt;/del&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/users.json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/orders.xml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;How to do it right:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/users&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/orders&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;As a more visual aid, following the conventions, we can use the following formula for naming our URLs:&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;/{collection} /{store} /{document}/{controller}&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Collection (plural):&lt;/strong&gt; A set of resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/books&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Store (plural):&lt;/strong&gt; Contains resources managed by the client (stores are not used as much):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/users/12/favorites&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Document (singular):&lt;/strong&gt; An instance in a collection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/books/2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/books/maths&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Controller (verb):&lt;/strong&gt; Executable functions (usually when we use controllers the HTTP method we use is POST):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/users/12/reset-password&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Complete example of how to name our endpoints:
&lt;/h2&gt;

&lt;p&gt;In this section we will see a complete example of an api design, first we will see how a bad REST API design would look like and then its correction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Before seeing how a well designed REST API would look like, correct yourself the errors of the badly designed API and compare at the end. This way you will learn more!&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;del&gt;&lt;em&gt;Poorly Designed API:&lt;/em&gt;&lt;/del&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Collection of books:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Obtain all books:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /getAllBooks&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Create a new book:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /createBook&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;A user's favorite books:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Get a specific user's favorite books:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /getUserFavorites?userId=12&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Add a book to the favorites of a specific user:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /addFavorite?userId=12&amp;amp;bookId=123&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Specific Book&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Obtain a specific book:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /getBookById?bookId=123&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Update a specific book:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /updateBook?bookId=123&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Delete a specific book:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /deleteBook?bookId=123&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Action/Controller in Specific Book&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Mark a book as read:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /markBookAsRead?bookId=123&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Request a loan extension:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /requestExtension?bookId=123&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Problems with Bad Design&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Verbs in URLs:&lt;/strong&gt; URLs should represent resources, not actions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inappropriate use of HTTP methods:&lt;/strong&gt; POST is used for update and delete, instead of PUT and DELETE.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use of query parameters:&lt;/strong&gt; Query parameters (?bookId=123) are being used instead of resource identifiers in the path.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;p&gt;Now we will see the API as it would be well designed.&lt;/p&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API well designed:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Book Collection:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Obtain all books:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /books&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Create a new book:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /books&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;User Favorite Books&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Get a specific user's favorite books:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /users/12/favorites&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Add a book to the favorites of a specific user:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /users/12/favorites&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Specific Book&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Obtain a specific book:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /books/123&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Update a specific book:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PUT /books/123&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Delete a specific book:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DELETE /books/123&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Action/Controller in Specific Book&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Mark a book as read:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /books/123/mark-as-read&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Request a loan extension:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /books/123/request-extension&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefits of Good Design&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clarity:&lt;/strong&gt; URLs are clear and represent resources.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Correct use of HTTP methods:&lt;/strong&gt; GET, POST, PUT, and DELETE are used properly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Identifiers in the path:&lt;/strong&gt; Resource identifiers are included in the path, not as query parameters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Logical structure:&lt;/strong&gt; The hierarchical and logical structure facilitates the understanding and use of the API.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;‎&lt;/p&gt;

&lt;p&gt;Thus, by following the right structure and proper use of HTTP methods, the well-designed API is more intuitive, scalable and easy to maintain.&lt;/p&gt;




&lt;p&gt;I hope this guide has provided you with the tools you need to design clear and consistent endpoints for your REST API. Good endpoint naming not only improves the user experience, but also facilitates the maintenance and scalability of your system. Remember that consistency and clarity are essential in API development. Don't forget to practice with the full example. Until next time, and happy coding!&lt;/p&gt;

</description>
      <category>api</category>
      <category>rest</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
