<?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: Stephen Nwankwo</title>
    <description>The latest articles on Forem by Stephen Nwankwo (@sten).</description>
    <link>https://forem.com/sten</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%2F839211%2F794f7968-9fde-4a84-a7f2-21c65ed2acd4.jpeg</url>
      <title>Forem: Stephen Nwankwo</title>
      <link>https://forem.com/sten</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sten"/>
    <language>en</language>
    <item>
      <title>The State of Security Protocols in Agent 2 Agent(A2A) Systems.</title>
      <dc:creator>Stephen Nwankwo</dc:creator>
      <pubDate>Sun, 05 Oct 2025 05:54:12 +0000</pubDate>
      <link>https://forem.com/sten/the-state-of-security-protocols-in-agent-2-agenta2a-systems-29km</link>
      <guid>https://forem.com/sten/the-state-of-security-protocols-in-agent-2-agenta2a-systems-29km</guid>
      <description>&lt;p&gt;If you are reading this, it's probably because you've heard or read something about Agentic AI sytems(and you care about security). Just so we are on the same page, Agentic AI sytems are autonomous entities capable of perceiving their environment, making decisions, and executing actions with minimal human intervention, typically with the help of an LLM(Large Languauge Model). And as for agent-2-agent agentic ai systems, you guessed it, it means exactly what it sounds like: multi-agent interaction and interoperability. As these intelligent agents increasingly interact and compose workflows across organizational, geographical, and trust boundaries(health and legal spaces), the demand for &lt;strong&gt;secure, standardized interoperability&lt;/strong&gt; becomes paramount. Without shared protocols governing identity, authentication, task exchange, and auditability, agent interactions are prone to fragmentation, redundancy, and critical security vulnerabilities such as impersonation, data exfiltration, and unauthorized privilege escalation.&lt;/p&gt;

&lt;p&gt;As we go, I will leave short side notes translating a few things to native SWE lingua, or general lingua.&lt;/p&gt;

&lt;p&gt;The cornerstone of modern Agent 2 Agent (A2A) security currently revolves around protocols that emphasize structured communication and identity awareness. One such foundational protocol is &lt;strong&gt;Google’s Agent-to-Agent (A2A) specification&lt;/strong&gt;, which provides a declarative, identity-aware framework designed for composability and trust.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Foundational A2A Protocol and Secure Interoperability
&lt;/h4&gt;

&lt;p&gt;The A2A protocol allows autonomous agents to discover each other via standardized &lt;strong&gt;AgentCards&lt;/strong&gt; [side note: kind of like a business card containing details about yourself, how to reach you and your role in the business. more on this later], authenticate using modern cryptographic protocols, and exchange tasks in a declarative, auditable manner [side note: I want to be abe to tell you what i want you to do, and i want to be able to tell when you do it]. The protocol facilitates communication between a Client Agent (formulating tasks) and a Remote Agent (acting on tasks). It is built on established web standards like HTTPS, JSON-RPC, and Server-Sent Events (SSE), prioritizing compatibility while adhering to a security-first approach.&lt;/p&gt;

&lt;p&gt;A core mechanism is the &lt;strong&gt;AgentCard&lt;/strong&gt;, a structured JSON metadata file located at the standardized path &lt;code&gt;/.well-known/agent.json&lt;/code&gt;. This card functions as a machine-readable "business card," containing identification, the A2A endpoint URL (&lt;code&gt;a2aEndpointUrl&lt;/code&gt;), detailed function catalogs, capability descriptions, and required authentication methods utilizing OpenAPI 3.x Security Scheme objects (e.g., &lt;code&gt;oauth2&lt;/code&gt;, &lt;code&gt;http bearer&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The standard A2A communication flow involves:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Discovery:&lt;/strong&gt; The client fetches the remote agent's AgentCard via HTTPS to learn its capabilities and authentication requirements. [side note: this is similar to a prefech done by web apps]&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Initiation:&lt;/strong&gt; The client authenticates (using the method specified in the AgentCard) and sends a JSON-RPC request over HTTPS via &lt;code&gt;tasks.send&lt;/code&gt; (synchronous) or &lt;code&gt;tasks.sendSubscribe&lt;/code&gt; (streaming updates using SSE). [side note: this is like sending a Bearer token in the header or X-API-Key along with your request, depending on the API specs]&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Processing &amp;amp; Interaction:&lt;/strong&gt; The server processes the task and returns the resulting Task object or streaming updates (TaskStatusUpdateEvent, TaskArtifactUpdateEvent).&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Assessing the Agentic Threat Landscape
&lt;/h4&gt;

&lt;p&gt;The autonomous nature of agentic AI required specialized security analysis, an entire system was birthed because of this. The &lt;strong&gt;MAESTRO&lt;/strong&gt; framework (Multi-Agent Environment, Security, Threat, Risk, and Outcome) is often leveraged for this purpose, providing a structured, granular, and proactive methodology tailored to the complexities of systems like those built using A2A. MAESTRO recognizes that security must be addressed across seven layers, from Foundation Models (Layer 1) up to the Agent Ecosystem (Layer 7). [side note: these layer methodology is similar to the 7 network layers in a way, but for agentic ai, just in case you're familiar with that.]&lt;/p&gt;

&lt;p&gt;The following image is a illustration of the 7 layers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx97ktlh6oa4kjhxxhn7j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx97ktlh6oa4kjhxxhn7j.png" alt="7 Layer Reference Architecture for Agentic AI" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Key A2A multi-agent system threats identified through MAESTRO include:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Threat&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;MAESTRO Layers&lt;/th&gt;
&lt;th&gt;Mitigation Focus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Agent Card Spoofing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An attacker publishes a forged Agent Card at a malicious domain, leading to task hijacking and data exfiltration.&lt;/td&gt;
&lt;td&gt;3 (Agent Frameworks), 4 (Deployment &amp;amp; Infrastructure)&lt;/td&gt;
&lt;td&gt;Digital Signatures, Secure Resolution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Poisoned AgentCard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Prompt injection techniques are embedded within AgentCard fields (like descriptions), causing another agent processing the card to execute hidden instructions.&lt;/td&gt;
&lt;td&gt;1 (Foundation Model), 2 (Data Operations)&lt;/td&gt;
&lt;td&gt;Input Sanitization, Schema Checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A2A Task Replay&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An attacker captures and replays a valid &lt;code&gt;tasks/send&lt;/code&gt; request, leading to duplicate or unauthorized actions.&lt;/td&gt;
&lt;td&gt;3 (Agent Frameworks), 2 (Data Operations)&lt;/td&gt;
&lt;td&gt;Nonces, Timestamp Verification, Idempotency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cross-Agent Task Escalation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A malicious agent attempts to escalate privileges by submitting tasks with forged credentials, breaching trust boundaries.&lt;/td&gt;
&lt;td&gt;7 (Agent Ecosystem), 3 (Agent Frameworks)&lt;/td&gt;
&lt;td&gt;Strict Authorization, Least Privilege&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you are a software engineer or a CS student, then the threats mentioned above probalbly sound like something you've heard before, e.g spoofing, SQL injection, CSRF, e.g..&lt;/p&gt;

&lt;h4&gt;
  
  
  Enhancing Security and Governance: Layered Architectures
&lt;/h4&gt;

&lt;p&gt;To address these vulnerabilities, robust protocols must integrate security deep within the system design right from the get-go. The goal is to develop a layered architecture that embeds governance and security across all system layers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero-Trust for Agent Interaction&lt;/strong&gt;&lt;br&gt;
The principle of &lt;strong&gt;Zero-Trust architecture&lt;/strong&gt;—"never trust, always verify"—is not new to software engineering and is essential for multi-agent systems, requiring continuous validation of identity and authorization for every agent, communication, and action. Implementation strategies include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Implementing &lt;strong&gt;strong authentication&lt;/strong&gt; mechanisms, ensuring each agent has a unique, cryptographically verifiable identity.&lt;/li&gt;
&lt;li&gt;  Applying &lt;strong&gt;fine-grained authorization controls&lt;/strong&gt; so agents receive only the minimum necessary permissions for their specific tasks [side note: if you are familiar with the Principle of Least Privilege, this is exactly what it entails).&lt;/li&gt;
&lt;li&gt;  Setting up &lt;strong&gt;encrypted communications&lt;/strong&gt; end-to-end (TLS/HTTPS) to prevent eavesdropping and message tampering, complemented by integrity checks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, with MAESTRO we are able to identify layers in A2A systems and the various angle of attacks by malicious users, the next obvious question would be how do we prevent these issues. The following paragraph outlines the security model thta have been agreed upon and put in place to curb these loop holes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SAGA: Granular Access Control and Oversight&lt;/strong&gt;&lt;br&gt;
While the A2A protocol facilitates decentralized identity and interoperability, it has been noted to lack policy enforcement mechanisms and runtime mediation of agent interactions.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;SAGA&lt;/strong&gt; (Security Architecture for Governing Agentic systems) architecture addresses this by enhancing governance and security through a Provider-mediated approach that gives &lt;strong&gt;users control and oversight&lt;/strong&gt; over their agents’ lifecycles. SAGA enables users to define an &lt;strong&gt;Access Contact Policy&lt;/strong&gt; (CP) for their agents, governing permissible incoming communication.&lt;/p&gt;

&lt;p&gt;SAGA integrates with A2A by protecting Agent Cards under user-specified access control policies and encapsulating A2A messages within its secure communication layer. Key to SAGA’s security model is the use of &lt;strong&gt;cryptographic access control tokens&lt;/strong&gt;. These tokens are generated by the receiving agent and encrypted using a dynamically derived shared key, providing fine-grained control over inter-agent communication and limiting the vulnerability window.&lt;/p&gt;

&lt;p&gt;This shared key derivation relies on One-Time Keys (OTKs) obtained from the Provider, which enforces the user's Contact Policy during the initial request. The token includes an expiration timestamp and a limit on the number of permitted requests (&lt;code&gt;Qmax&lt;/code&gt;), which allows tokens to be reused for subsequent communication without involving the centralized Provider, here bybalancing security and performance overhead.&lt;/p&gt;
&lt;h4&gt;
  
  
  Workflow Illustration: Secure A2A Task Delegation using SAGA/Policy Enforcement
&lt;/h4&gt;

&lt;p&gt;The following diagram illustrates the flow required to establish secure communication for a delegated A2A task, incorporating the cryptographic policy enforcement mechanisms found in SAGA.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fktygkbmhqh6ed6l5xbes.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fktygkbmhqh6ed6l5xbes.png" alt="Secure A2A Task Delegation using SAGA/Policy Enforcement" width="800" height="688"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Secure Implementation: Code Controls
&lt;/h4&gt;

&lt;p&gt;Secure implementation of an A2A Server requires rigorous validation of inputs, tokens, and authorization against threats like replay attacks and token misuse. Agent frameworks should apply controls such as input sanitization to all AgentCard content to mitigate poisoned AgentCard risks. Furthermore, strong token and task validation is crucial.&lt;/p&gt;

&lt;p&gt;The following pseudo-code illustrates essential server-side logic for handling an incoming request that carries an Access Control Token, incorporating checks recommended for mitigating replay and misuse threats:&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="c1"&gt;# Function to validate the Access Control Token (ACT) attached to an A2A request
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_access_token&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initiating_agent_id&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request_nonce&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Validates the cryptographic token against expiry, quota, and identity.
    Mitigates: A2A Task Replay, Authentication &amp;amp; Identity Threats, Token Misuse.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="c1"&gt;# 1. Decrypt token using shared key (SDHK, derived during initial handshake)
&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;decrypted_claims&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;decrypt_token &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SDHK&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;DecryptionError&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&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 token encryption. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. Check Expiration Time (Texpire)
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;decrypted_claims&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; Texpire &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nf"&gt;current_timestamp &lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; Token has expired. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# 3. Check Initiating Agent Identity (PACB)
&lt;/span&gt;    &lt;span class="c1"&gt;# Ensures the token wasn't issued to a different agent (mitigates A5)
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;decrypted_claims&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; PACB &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;initiating_agent_id&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; Token issued for different agent identity. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# 4. Check Usage Quota (Qmax)
&lt;/span&gt;    &lt;span class="c1"&gt;# Requires backend storage to track remaining requests against Qmax
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;get_token_usage &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;decrypted_claims&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; Qmax &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="c1"&gt;# If quota is exceeded, the token is invalid (A3)
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; Token usage quota exceeded. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# 5. Check for Nonce/Task Replay (Mitigation for A2A Task Replay)
&lt;/span&gt;    &lt;span class="c1"&gt;# If the request used a nonce, ensure it hasn't been seen recently.
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request_nonce&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;is_nonce_replayed &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;request_nonce&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initiating_agent_id&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; Replayed request nonce detected. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# 6. If all checks pass, increment usage and proceed.
&lt;/span&gt;    &lt;span class="nf"&gt;increment_token_usage &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; Token Valid. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;By adopting security frameworks like MAESTRO, layering Zero-Trust principles, and implementing specialized protocols like A2A, augmented by fine-grained control systems such as SAGA, developers can build robust and trustworthy security protocols essential for the next generation of autonomous agent systems.&lt;/p&gt;




&lt;p&gt;Thank you for reading, and may the Force be with you.&lt;/p&gt;




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

&lt;p&gt;&lt;a href="https://cloudsecurityalliance.org/blog/2025/02/06/agentic-ai-threat-modeling-framework-maestro" rel="noopener noreferrer"&gt;https://cloudsecurityalliance.org/blog/2025/02/06/agentic-ai-threat-modeling-framework-maestro&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://arxiv.org/html/2504.21034v2#S3" rel="noopener noreferrer"&gt;https://arxiv.org/html/2504.21034v2#S3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://a2a-protocol.org/dev/specification/" rel="noopener noreferrer"&gt;https://a2a-protocol.org/dev/specification/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://a2aprotocol.ai/docs/guide/a2a-protocol-specification-python" rel="noopener noreferrer"&gt;https://a2aprotocol.ai/docs/guide/a2a-protocol-specification-python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=56BXHCkngss" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=56BXHCkngss&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Where to find me:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/stephen-nwankwo-9876b4196/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/stephen-nwankwo-9876b4196/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/Sage_Sten" rel="noopener noreferrer"&gt;https://x.com/Sage_Sten&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/sten"&gt;https://dev.to/sten&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/stenwire" rel="noopener noreferrer"&gt;https://github.com/stenwire&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>gemini</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Building an MCP Server with RAG Capabilities for Developer Tools</title>
      <dc:creator>Stephen Nwankwo</dc:creator>
      <pubDate>Sun, 06 Jul 2025 19:34:06 +0000</pubDate>
      <link>https://forem.com/sten/building-an-mcp-server-with-rag-capabilities-for-developer-tools-17g8</link>
      <guid>https://forem.com/sten/building-an-mcp-server-with-rag-capabilities-for-developer-tools-17g8</guid>
      <description>&lt;p&gt;As the demand for intelligent, context-aware assistants grows, the need for flexible and modular agent protocols has never been more critical. With this article and project, I hope to demonstrate how easy it is to combine MCP + RAG to aid knowledge-grounded responses whiile working across various development environments such as VS Code, Claude, Cursor, etc..&lt;/p&gt;

&lt;p&gt;This article is a very high-level overview of the project, the architecture, and how this hybrid system can be embedded into developer tools seamlessly.&lt;/p&gt;




&lt;h3&gt;
  
  
  What is MCP?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;MCP (Model Context Protocol)&lt;/strong&gt;, invented by a team at Anthropic is an emerging standard for enabling consistent interaction between AI agents and their environments. Designed to separate environment logic from model behavior, MCP allows tools like IDEs and terminal clients to interact with LLMs in a structured way, similar to how the LSP (Language Server Protocol) standardized code intelligence or how REST standardized Client-API interaction. A lot of people like to refer to MCP as the USB-C of Agent - to - external tool interaction, I hope you  get the idea.&lt;/p&gt;

&lt;p&gt;There are two major parts that make up an MCP, the first is the Server and the second is the Host(aka Client), the former houses the interface that connects to all the external/internal tools, while the Host houses the interfaces responsible for connecting to the server and translating user input to commands to be sent to the server. The image below is an illustration of what a basic MCP architecture looks like.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdlyk8req53sk7jb5e2rx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdlyk8req53sk7jb5e2rx.png" alt="MCP Architecture" width="800" height="611"&gt;&lt;/a&gt;&lt;br&gt;
figure(1)&lt;/p&gt;

&lt;p&gt;Connecting the Server to the Host typically involves writing a JSON data to the host MCP configuration or settings.json in the case of VsCode(what I used). The typical structure of the Json configuration looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"name-of-mcp-server": {
    "type": "protocol",
    "command": "run_command",
    "args": [
        "url_or_file_path_to_server"
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  What is RAG?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Retrieval-Augmented Generation (RAG)&lt;/strong&gt; combines a language model with an external knowledge retriever. Instead of relying solely on the model's training data, RAG systems pull relevant documents or facts in real-time to augment the prompt. This helps particularly to improve response accuracy, reduces hallucinations, and makes models useful in specialized domains.&lt;/p&gt;




&lt;h3&gt;
  
  
  Project Overview
&lt;/h3&gt;

&lt;p&gt;This project involves building an &lt;strong&gt;MCP server&lt;/strong&gt; that wraps a RAG pipeline. Any client or host that supports MCP can interface with this server to ask questions, perform searches, or generate context-aware completions.&lt;/p&gt;

&lt;p&gt;The goal is to provide local or self-hosted intelligence that can adapt to your documents, codebase, or domain knowledge without relying on external APIs.&lt;/p&gt;




&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmhc44mso03tzbau7s1q7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmhc44mso03tzbau7s1q7.png" alt="MCP-RAG workflow" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
figure(2)&lt;/p&gt;

&lt;p&gt;The MCP server handles structured requests, transforms them into a context-aware prompt using the RAG system, and returns enriched responses back to the client.&lt;/p&gt;




&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;

&lt;p&gt;For this project, I built an MCP-RAG server that helps to answer questions related to documenting Django Rest Framework(DRF) APIs&lt;/p&gt;

&lt;p&gt;Here's a breakdown of the tech stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Major Library&lt;/strong&gt;: Google ADK, langchain, python mcp sdk, chroma(for vectore store).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MCP Protocol&lt;/strong&gt;: Custom implementation based on official spec from Anthropic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;RAG Stack&lt;/strong&gt;:&lt;br&gt;
Google ADK with gemini is used to handle embedding and retrieval, langchain is used for chuking text and the vector store used is Chroma DB&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Client Interface&lt;/strong&gt;: VsCode configured using the standard MCP JSON config.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Here's what the file structure looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3x14d64x760zjfxq9tgr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3x14d64x760zjfxq9tgr.png" alt="File Structure" width="590" height="361"&gt;&lt;/a&gt;&lt;br&gt;
figure(3)&lt;/p&gt;

&lt;p&gt;Here’s an example exchange inside VS Code using the MCP RAG server:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9lc02u6sg1zm6zy0t2f9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9lc02u6sg1zm6zy0t2f9.png" alt="VsCode chat UI" width="800" height="740"&gt;&lt;/a&gt;&lt;br&gt;
figure(4)&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Cases
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ask domain-specific questions, get code explanations, or retrieve documentation instantly.&lt;/li&gt;
&lt;li&gt;Query internal knowledge bases while chatting.&lt;/li&gt;
&lt;li&gt;Integrate organization-specific coding guidelines and FAQs into Cursor's/CoPilot LLM responses.
All of these, while in your code editor.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This project is a step toward plug-and-play intelligence across your developer stack. By combining the modular power of MCP with the contextual strength of RAG, you can build assistants that actually understand your codebase, your docs, your workflows.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Resources&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Link to Code:&lt;/strong&gt; &lt;a href="https://github.com/stenwire/MCP/tree/main/django-mcp" rel="noopener noreferrer"&gt;https://github.com/stenwire/MCP/tree/main/django-mcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/anthropics/mcp" rel="noopener noreferrer"&gt;MCP Spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.latent.space/p/rag" rel="noopener noreferrer"&gt;Intro to RAG&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://google.github.io/adk-docs/get-started/" rel="noopener noreferrer"&gt;Google ADK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.langchain.com/" rel="noopener noreferrer"&gt;LangChain &amp;amp; LlamaIndex (for RAG)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>mcp</category>
      <category>rag</category>
    </item>
    <item>
      <title>Optimizing SQL queries for your AI Agents.</title>
      <dc:creator>Stephen Nwankwo</dc:creator>
      <pubDate>Sun, 11 May 2025 19:51:47 +0000</pubDate>
      <link>https://forem.com/sten/optimizing-sql-queries-for-your-ai-agents-41dj</link>
      <guid>https://forem.com/sten/optimizing-sql-queries-for-your-ai-agents-41dj</guid>
      <description>&lt;p&gt;So, you're building the next generation of Agentic AI, a smart, autonomous system ready to understand, reason, and act. Fantastic! But where does this digital brain get its crucial "proprietary knowledge" or the specific context it needs to make intelligent decisions? Often, it's from your trusty SQL database, queried to pull in everything from user history and product catalogs to real-time sensor data that forms the bedrock of its understanding.&lt;/p&gt;

&lt;p&gt;You've designed your agent, given it goals, and it's ready to interact. But then... the pause. That moment your agent needs to "think" to fetch that vital piece of information from the database to build context and it feels like an eternity. Your sophisticated agent, designed for dynamic action, is suddenly hamstrung by a slow SQL query, turning its "real-time" reasoning into "just-a-minute" frustration. This, my friends, is where SQL query optimization becomes absolutely critical for potent Agentic AI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fov3r3hb62qvl7kyyp8x3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fov3r3hb62qvl7kyyp8x3.jpg" alt="A meme about slow sql queries" width="500" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's like tasking a brilliant detective with solving a case, but every time they need a clue (a piece of data), they have to manually sift through mountains of unsorted files in a dusty archive. The detective is smart, but the information retrieval is crippling their speed and effectiveness. Our agents are no different.&lt;br&gt;
How do we ensure our AI agents get their context fast and efficiently? Drawing from alrady existing solid optimization principles, let's look at the game plan:&lt;/p&gt;
&lt;h4&gt;
  
  
  Become a Data Profiler with &lt;code&gt;EXPLAIN&lt;/code&gt;:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Before your agent can act intelligently, you need to understand how it's getting its intelligence. &lt;code&gt;EXPLAIN&lt;/code&gt; (or its equivalent) unveils the database's strategy for fetching data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Red Flag for Agents: Is it scanning millions of rows for a small piece of context your agent needs right now? That's a bottleneck that directly impacts agent responsiveness.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Costly &lt;code&gt;SORT&lt;/code&gt; Operations: If the agent needs sorted data for its logic, these can be memory hogs, slowing down the entire context-building process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Full Table Scans: The arch-nemesis! Your agent shouldn't wait for the DB to read an entire table to understand a specific situation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Sharpen the Agent's Focus (Tune the Query Itself!):
&lt;/h4&gt;

&lt;p&gt;This is often where the biggest wins for agent performance lie.&lt;br&gt;
Filter with Precision (&lt;code&gt;WHERE&lt;/code&gt; clause): Equip your agent's queries to be surgical. Only fetch the exact data needed for the current task or decision. The more targeted the &lt;code&gt;WHERE&lt;/code&gt; clause, the faster the context is built.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Efficient &lt;code&gt;JOIN&lt;/code&gt;s: If your agent needs to combine information from multiple tables (e.g., user profile + interaction history), ensure those JOINs are lean and mean.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Concise &lt;code&gt;IN&lt;/code&gt; Lists: If your agent is checking against a set of known items, keep that list tight.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Create Fast-Access Lanes with Indexes:
&lt;/h4&gt;

&lt;p&gt;Think of indexes as creating a super-efficient filing system for the data your agent frequently needs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Identify columns your agent often uses for lookups in its &lt;code&gt;WHERE&lt;/code&gt; clauses or to &lt;code&gt;ORDER BY&lt;/code&gt; for its reasoning. Indexing these is like giving your agent a direct line to the information.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Agent Benefit: &lt;strong&gt;Faster context retrieval = quicker decision-making = a more responsive and seemingly "smarter" agent&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Caution: Don't just slap indexes everywhere. They speed up reads (good for agents fetching context) but can slow down writes. Use &lt;code&gt;EXPLAIN&lt;/code&gt; to validate their impact.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Major Overhauls for Complex Agent Needs:
&lt;/h4&gt;

&lt;p&gt;When agents deal with massive, evolving datasets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Table Partitioning: If your agent reasons over time-series data (e.g., daily user activity), partitioning by date can mean it only queries the relevant recent slice of data, dramatically speeding up context gathering.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Data Structure Redesign: Sometimes, the way data is structured needs to align better with how your agent thinks and accesses information. This is a deep dive, but for complex agents, it can be transformative.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you dev with python like myself, here's how to how to use &lt;code&gt;EXPLAIN&lt;/code&gt; to inspect potential performance bottlenecks like full table scans and costly sorts, which can directly affect AI agent responsiveness.&lt;/p&gt;

&lt;p&gt;Suppose you have postgres setup somewhere and your table schema looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;NOW&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;Create a python file and enter this:&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;psycopg2&lt;/span&gt;

&lt;span class="c1"&gt;# Connect to your PostgreSQL database
&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;psycopg2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;dbname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_db&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5432&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;cur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# The actual query the AI agent might run
&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
SELECT * FROM documents
WHERE content ILIKE &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%recycling%&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;
ORDER BY created_at DESC
LIMIT 10;
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="c1"&gt;# Use EXPLAIN ANALYZE to see what PostgreSQL does under the hood
&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EXPLAIN (ANALYZE, BUFFERS, VERBOSE) &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="si"&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;plan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Query Plan:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&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;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Save and run the file, then observe the result. And if you are not understanding what you are seeing, you know what to do.&lt;/p&gt;

&lt;h4&gt;
  
  
  My Takeaway for AI Devs:
&lt;/h4&gt;

&lt;p&gt;For Agentic AI, the speed and efficiency of data retrieval for context building are not just "database concerns", they are core to agent performance. A slow query means a slow-thinking agent, leading to poor user experience or ineffective automation. Regularly optimizing the SQL queries that feed your agents is like sharpening their cognitive tools. Use &lt;code&gt;EXPLAIN&lt;/code&gt; religiously, prioritize query tuning and intelligent indexing.&lt;/p&gt;

&lt;p&gt;How are you ensuring your agents get the data they need, when they need it, without the lag? Share your strategies for performant context-building! 👇&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect with me on:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/stephen-nwankwo-9876b4196/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/Sage_Sten" rel="noopener noreferrer"&gt;X(Twitter)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/stenwire" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>sql</category>
      <category>python</category>
      <category>database</category>
    </item>
    <item>
      <title>Learn Google ADK: Build a farming agent.</title>
      <dc:creator>Stephen Nwankwo</dc:creator>
      <pubDate>Sun, 20 Apr 2025 05:02:32 +0000</pubDate>
      <link>https://forem.com/sten/learn-google-agent-adk-build-a-farming-agent-pc8</link>
      <guid>https://forem.com/sten/learn-google-agent-adk-build-a-farming-agent-pc8</guid>
      <description>&lt;h1&gt;
  
  
  Meet NaijaFarmHand: Your AI Farming Buddy for Nigeria
&lt;/h1&gt;

&lt;p&gt;Ever felt overwhelmed starting a small farm? Wondering when the best time to plant your maize is, what you &lt;em&gt;actually&lt;/em&gt; need to start raising chickens, or what the weather will be like tomorrow in your specific town? Getting practical, localized farming information can sometimes feel like searching for a needle in a haystack, especially when you're just starting out.&lt;/p&gt;

&lt;p&gt;Imagine having a helpful assistant, powered by Artificial Intelligence (like the technology behind ChatGPT or Google Gemini), specifically designed to answer your beginner farming questions within the Nigerian context. This project isn't about replacing experienced farmers or extension agents, but about providing a quick, accessible first point of contact for common queries.&lt;/p&gt;

&lt;p&gt;Built using Google's AI Development Kit (ADK) and running within a Kaggle Notebook environment (a popular platform for data science and AI projects), NaijaFarmHand aims to bridge the information gap for aspiring and early-stage farmers focusing on some of Nigeria's key agricultural products.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before we dive in, here’s a bit of background: this project was completed as part of the 5-Day Gen AI Intensive course by Google.&lt;/p&gt;

&lt;p&gt;If you want to jump straight to the code, find link to the kaggle notebook at the end of the article.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What Can NaijaFarmHand Actually Do?
&lt;/h2&gt;

&lt;p&gt;Think of NaijaFarmHand as having a few specialized skills, like different tools in a farmer's toolkit. It's specifically focused on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Crops:&lt;/strong&gt; Maize, Cassava, Yam, Groundnut, and Guinea Corn.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Livestock:&lt;/strong&gt; Poultry (Broiler and Layer Chickens).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you ask about growing strawberries or raising snails, it will politely tell you that's outside its current expertise but might try to find general information using Google Search.&lt;/p&gt;

&lt;p&gt;Here are its main "tools":&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;WeatherTool&lt;/code&gt; - The Local Forecaster:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;What it does:&lt;/strong&gt; Gets you the &lt;em&gt;current&lt;/em&gt; weather conditions for a specific Nigerian location. Need to know if it's likely to rain in Ibadan today before planting? Ask NaijaFarmHand, and it will use this tool.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Why it's important:&lt;/strong&gt; Weather is critical for day-to-day farming decisions. This tool uses the OpenWeatherMap API (powered by a secret API key safely stored using Kaggle Secrets) to fetch real-time data.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;FarmPlannerTool&lt;/code&gt; - The Starter Checklist Generator:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;What it does:&lt;/strong&gt; Provides a &lt;em&gt;basic&lt;/em&gt; checklist of things to consider when starting a specific type of farm (from its focus list) at a particular scale (e.g., "small scale maize farm" or "50 broiler chickens").&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Why it's important:&lt;/strong&gt; Gives beginners a rough idea of requirements like land, basic capital estimates (with a big disclaimer that costs vary!), simple tools, and initial inputs. It helps structure initial planning.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;TimingAdvisorTool&lt;/code&gt; - The Seasonal Guide:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;What it does:&lt;/strong&gt; Offers &lt;em&gt;general&lt;/em&gt; advice on typical planting seasons and harvest times for its focus crops in different broad regions of Nigeria (North, Middle Belt, South).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Why it's important:&lt;/strong&gt; Helps understand the usual agricultural calendar. &lt;strong&gt;Crucially&lt;/strong&gt;, NaijaFarmHand is programmed to &lt;em&gt;always&lt;/em&gt; remind you that this is general advice and you MUST check the current local weather (using the &lt;code&gt;WeatherTool&lt;/code&gt;) and talk to local farmers for precise timing. Climate varies!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;google_search_grounding&lt;/code&gt; - The Researcher:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;What it does:&lt;/strong&gt; For questions that the other tools can't answer directly, NaijaFarmHand uses Google Search. This is used for finding details on specific crop varieties suitable for Nigeria, identifying pests/diseases, getting an &lt;em&gt;idea&lt;/em&gt; of market prices (which fluctuate wildly!), or learning about government agricultural programs.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Why it's important:&lt;/strong&gt; Provides a way to access the vast information online, guided by the agent's instructions to find relevant answers for the user.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  How Does It All Work Together?
&lt;/h2&gt;

&lt;p&gt;You don't need to be an AI expert to understand the basics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;The Brain:&lt;/strong&gt; The project uses a powerful language model from Google ("gemini-1.5-pro") as the core intelligence.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The Instructions:&lt;/strong&gt; We give the AI very specific instructions (the &lt;code&gt;agent_instructions&lt;/code&gt; block you saw) telling it &lt;em&gt;who&lt;/em&gt; it is (NaijaFarmHand), &lt;em&gt;what&lt;/em&gt; its job is, &lt;em&gt;what&lt;/em&gt; topics it should cover, and &lt;em&gt;how&lt;/em&gt; to use its tools.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The Framework (Google ADK):&lt;/strong&gt; This is like the plumbing and wiring. It provides the structure (&lt;code&gt;Agent&lt;/code&gt;, &lt;code&gt;Runner&lt;/code&gt;, &lt;code&gt;SessionService&lt;/code&gt;) to define the agent, connect the tools, manage the conversation flow, and remember what was said previously in the chat (&lt;code&gt;InMemorySessionService&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The Interaction:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  You type a question (e.g., "What do I need for a small backyard poultry farm?").&lt;/li&gt;
&lt;li&gt;  The &lt;code&gt;Runner&lt;/code&gt; passes this to the &lt;code&gt;Agent&lt;/code&gt; (NaijaFarmHand).&lt;/li&gt;
&lt;li&gt;  The &lt;code&gt;Agent&lt;/code&gt;, guided by its instructions, decides which tool is best. In this case, probably the &lt;code&gt;FarmPlannerTool&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  It calls the tool, gets the checklist back.&lt;/li&gt;
&lt;li&gt;  It formats the checklist into a friendly response.&lt;/li&gt;
&lt;li&gt;  The &lt;code&gt;Runner&lt;/code&gt; delivers the response back to you.&lt;/li&gt;
&lt;li&gt;  If you asked "What's the weather in Kano?", it would use the &lt;code&gt;WeatherTool&lt;/code&gt;. If you asked "Tell me about Fall Armyworm control in Maize," it would likely use the &lt;code&gt;google_search_grounding&lt;/code&gt; tool.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Why Build Something Like NaijaFarmHand?
&lt;/h2&gt;

&lt;p&gt;This project demonstrates how modern AI tools can be tailored to solve specific, localized problems. It's about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Accessibility:&lt;/strong&gt; Making basic farming information readily available through a simple chat interface.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Localization:&lt;/strong&gt; Focusing specifically on Nigerian crops, conditions, and context.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Practicality:&lt;/strong&gt; Integrating tools like weather and planning checklists directly into the conversation.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Learning:&lt;/strong&gt; It's a great example of building agents with multiple tools using the Google ADK framework.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While NaijaFarmHand is a prototype running in a notebook, it showcases the potential for AI to support agriculture and empower individuals starting their farming journey in Nigeria. It emphasizes providing helpful guidance while always encouraging users to seek detailed, local expert advice for critical decisions.&lt;/p&gt;




&lt;p&gt;Link to Kaglle Notebook: &lt;a href="https://www.kaggle.com/code/stephennwankwo/naijafarmhand-agent" rel="noopener noreferrer"&gt;https://www.kaggle.com/code/stephennwankwo/naijafarmhand-agent&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More about Google ADK: &lt;a href="https://google.github.io/adk-docs/" rel="noopener noreferrer"&gt;https://google.github.io/adk-docs/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>kaggle</category>
      <category>adk</category>
      <category>ai</category>
    </item>
    <item>
      <title>Performance Testing: Is Your API Ready for Real-World Traffic?</title>
      <dc:creator>Stephen Nwankwo</dc:creator>
      <pubDate>Mon, 06 Jan 2025 08:25:57 +0000</pubDate>
      <link>https://forem.com/sten/performance-testing-is-your-api-ready-for-real-world-traffic-4e9p</link>
      <guid>https://forem.com/sten/performance-testing-is-your-api-ready-for-real-world-traffic-4e9p</guid>
      <description>&lt;p&gt;Have you ever had the thought of simulating real-life users on your API or service, or have you ever wanted to put your API to the test, to see how much it can and can not handle, to make informed decisions, like optimize your code better or consider scaling your server, horizontally or vertically? Well, I have, on multiple occasions, but apart from writing unit and e2e tests, I have never really gone ahead to run actual performance tests, the reasons being we usually had a QA engineer on the team, and for personal projects, I felt nonchalant and convinced myself it wasn’t necessary.&lt;/p&gt;

&lt;p&gt;But here's the issue: It's not about whether I need it in my personal project that will never get up to 5 active users; it's about giving myself a chance to learn something new. I believe having this knowledge/skill will really make you stand out as a software engineer or backend engineer&lt;/p&gt;

&lt;p&gt;Knowing how to test your API performance will help solidify your knowledge of whatever technology or framework you're using to build. When you run a test, you notice an issue, and then you go back to your IDE to figure out if it's a query, a join statement, or data manipulation logic that's the issue, you start to ask yourself questions and dig deeper, you select better data structures, you improve your SQL statements, you consider implementing caching, you realize you're making multiple calls to the DB for the same items, and you realize your code structure is looking like a plate of spaghetti from the Bear movie. At the end of all these, you come out a bad-ass engineer. What you learn from performance testing is endless.&lt;/p&gt;

&lt;p&gt;I am a backend-heavy software engineer. If you ask me who a backend engineer is in 2025, my answer would be someone who does backend work, understands systems design, is knowledgeable about best dev-ops practices and performance testing, and has a good background in data structures and algorithms. So you need this stuff if you really want to skill up, scale up, and take up senior roles.&lt;/p&gt;




&lt;h2&gt;
  
  
  What are the types of performance testing?
&lt;/h2&gt;

&lt;p&gt;Before I go on to the types of performance testing, I want to mention that the first step to actually testing your API's performance is by writing proper unit, integration, and e2e tests, and making sure to cover as many edge cases as possible. I know it's for functionality, but come on, you don't have those ones present and you're bothered about performance?&lt;/p&gt;

&lt;p&gt;Now, to address the elephant in the room, there are various types of performance testing as shown below. For easy understanding and brevity, I used the explain-example-result format.&lt;/p&gt;




&lt;p&gt;So, let's start with &lt;strong&gt;load testing&lt;/strong&gt;, which is primarily carried out to evaluate how a system performs under expected user loads or usage.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You are launching an e-commerce website, and you expect 500 users to browse and shop simultaneously during peak hours.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A load test simulates 500 concurrent users browsing the site, adding items to carts, and checking out.
&lt;/li&gt;
&lt;li&gt;Metrics: Response time, database query times, and server resource utilization under this expected load.
&lt;/li&gt;
&lt;li&gt;Goal: By identifying slow database queries or underperforming endpoints during load testing, you can optimize these areas to provide a seamless user experience, preventing potential revenue loss during high-traffic periods.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;We have tested the system's capability in handling a normal scenario, or expected usage level. Now we want to find out the system's breaking point, by applying a load beyond its capability. That's where &lt;strong&gt;Stress Testing&lt;/strong&gt; comes in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You want to understand how your social media platform handles traffic spikes, such as during a viral event.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A stress test simulates 50,000 users simultaneously posting, liking, and commenting—far exceeding normal user activity.
&lt;/li&gt;
&lt;li&gt;Metrics: System stability, error rates, and recovery time after failure.
&lt;/li&gt;
&lt;li&gt;Goal: By conducting stress tests, you gain insights into failure thresholds and recovery strategies, which are crucial for maintaining user trust and business continuity during high-demand scenarios.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;There are cases where we might be expecting the system usage or traffic to increase, maybe double or triple, and you want to make sure you have everything in place, that's what &lt;strong&gt;Scalability Testing&lt;/strong&gt; is for, to test the system's ability to scale up or down with increased load or resource availability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Your video streaming app plans to add 1 million users next year, doubling the current base.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A scalability test increases the number of concurrent users incrementally (e.g., 10,000 to 50,000) and observes system performance.
&lt;/li&gt;
&lt;li&gt;Metrics: Server response times, database performance, and horizontal or vertical scaling efficiency.
&lt;/li&gt;
&lt;li&gt;Goal: Scalability testing helps validate whether your infrastructure investments, such as autoscaling or database sharding, are effective and ensure the app remains competitive as user demands grow.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;And now, &lt;strong&gt;Volume Testing&lt;/strong&gt; ---If you're expecting a large number of users, or your application is data intensive, you probably want to make sure your system can handle a high volume of data and still maintain optimal performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Your financial application must process and store 10 million daily transactions.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A volume test loads the database with a large dataset (10 million transaction records) and tests retrieval, updates, and queries.
&lt;/li&gt;
&lt;li&gt;Metrics: Query execution time, disk I/O, and database index performance.
&lt;/li&gt;
&lt;li&gt;Goal: By validating database performance under high data loads, volume testing ensures seamless operations for end-users and reduces the risk of downtime during critical transactions.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Lastly, we have &lt;strong&gt;Endurance Testing (Soak Testing)&lt;/strong&gt; which is usually carried out to check the system's stability and performance over an extended period.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Your online gaming platform needs to handle 20,000 concurrent players for 48 hours without downtime or memory leaks.&lt;br&gt;
An endurance test simulates continuous gameplay by 20,000 users, including saving progress and multiplayer interactions, over two days.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Metrics: Memory usage, CPU utilization, and error rates over time.
&lt;/li&gt;
&lt;li&gt;Goal: By uncovering resource leaks or degradation, endurance testing helps maintain user satisfaction and avoids costly downtime, especially in critical applications requiring high availability."&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Now that you have discovered some issues in your project, resolving them should be the next thing on your agenda. There are various ways to resolve these issues, some of which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Query Optimization:&lt;/strong&gt;&lt;br&gt;
Here, you want to go back to IDE to improve the efficiency of your DB queries, and access patterns which may have resulted in an ~N+1 selects problem~.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bottleneck Analysis:&lt;/strong&gt;&lt;br&gt;
Bottleneck Analysis is usually the go-to first step because it identifies specific parts of a system (hardware or software) that limit performance, and suggests targeted optimizations like indexing, query restructuring, or load balancing. During bottleneck analysis, you're able to pin-point low database queries, overloaded threads, or network latency&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Call Tree:&lt;/strong&gt;&lt;br&gt;
A call tree analysis will help you resolve issues that arise from a hierarchical representation of function calls, such as situations where functions call others and for some reason that process takes a long time to resolve.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resource Contention Analysis:&lt;/strong&gt;&lt;br&gt;
Resource Contention Analysis involves examining how shared resources (e.g., CPU, memory, database connections) are utilized and if contention arises. It helps to identify race conditions or deadlocks under high loads and to optimize thread pools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Diagnostics:&lt;/strong&gt;&lt;br&gt;
Perhaps you have some diagnostic services like Sentry, New Relic, Datadog, or Prometheus set up in your server, diagnostics involve collecting and analyzing logs, traces, and metrics from these services to identify the root cause of issues during performance testing&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Platforms and Tools for performance testing
&lt;/h2&gt;

&lt;p&gt;There are a lot of these tools available, but in other to keep this article short, I will have to mention a few.&lt;/p&gt;

&lt;p&gt;In order to run performance testing, you have to leverage tools like PyCharm Profiler / Django Debug Toolbar to pinpoint performance issues in code, k6(Great for APIs and microservices), Load Runner, Locust(for Python), BlazeMeter(Can be integrated in CI/CD pipelines), HammerDB and Database Benchmark for volume testing. &lt;/p&gt;

&lt;p&gt;To select which is best for you, consider your technology stack, the scale of the project, ease of use, and your budget(K6, JMeter, and Locust are the go-tos because they are cost-effective and open-source).&lt;/p&gt;




&lt;p&gt;Each type of testing ensures your service is prepared for different real-world scenarios, from handling normal traffic to extreme and prolonged conditions. &lt;/p&gt;

&lt;p&gt;If you found this article useful, please consider leaving a like or a comment to share your thoughts, opinions, or experience in performance testing.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Understanding Row-level locking in databases.</title>
      <dc:creator>Stephen Nwankwo</dc:creator>
      <pubDate>Wed, 16 Oct 2024 16:43:46 +0000</pubDate>
      <link>https://forem.com/sten/understanding-row-level-locking-in-databases-2c8j</link>
      <guid>https://forem.com/sten/understanding-row-level-locking-in-databases-2c8j</guid>
      <description>&lt;p&gt;Recently, on an ongoing side project, I was tasked with implementing endpoints to manage API Keys, one of the main requirements is to enforce a limit to the number of keys that can be allocated to a user. The obvious way to approach this would be creating a global variable carrying the maximum number of requestable keys and then checking for the number of user keys in the database against the value of that variable when the create endpoint is queried, then a key is allocated to the user or not. That should be about it, right? No! I would later find out; that enforcing that API key limit would take more than that. This is where row-level locking comes in.&lt;/p&gt;

&lt;p&gt;Assume that you are a boring person (you are, and you know it) and only have two friends. One of your friends (let's call him Samuel) who traveled had told you and Ahmed (your second friend) that he had an item delivered to him awaiting pickup, but only one of you is to take his place and pick up the item. Because you're a boring and annoying person, you and Ahmed had a heated argument and stopped talking two days before one of you was supposed to go pick up the item. Unsure as to who will go, because you two had failed to communicate that because of the argument, you both choose to act independently even though you knew that only one of you should go as instructed by Joseph. You go out to do it yourself because you think your friend won't pick it up. Simultaneously, your friend departs with an identical thought process.&lt;/p&gt;

&lt;p&gt;You are both surprised to encounter each other at the pickup station, as well as perplexed. Even worse, the station's attendant is unsure about who to give the item to.&lt;/p&gt;

&lt;p&gt;Since the terms of the agreement were unclear, this has disrupted the process of obtaining the item. You two have no idea what the other is doing, and if you had coordinated and communicated earlier, this uncertainty would have been averted.&lt;/p&gt;




&lt;p&gt;In database terms, this is what happens when row-level locking isn't used properly during critical operations. If multiple requests (like you and your friend) try to access or update the same piece of data (pick up the item), without row-level locking, there's no coordination or restriction to prevent them from working on the same record simultaneously. This can lead to race conditions, data inconsistency, or even conflicts that disrupt the intended workflow.&lt;/p&gt;

&lt;p&gt;The case between you and your friend, with the lack of communication, can be tied to the need for setting up row-level locking on the endpoint that handles creating an API key, so as to not allow un-intentional or malicious concurrent request try to bypass the limit.&lt;/p&gt;



&lt;h2&gt;
  
  
  What is row locking?
&lt;/h2&gt;

&lt;p&gt;By now, you probably have an overview as to what row-level locking is, row-level locking is one of three levels of data locking that involves managing access to the modification or retrieval of a particular item or row, whilst allowing other rows that do not need to be accessed. Other levels of data locking are table locking and page locking. Row-level locking is widely praised over the other two because it increases concurrency and availability by allowing more transactions to access and modify the same table concurrently, without blocking or waiting for each other.&lt;/p&gt;
&lt;h2&gt;
  
  
  Types of row locking
&lt;/h2&gt;

&lt;p&gt;Row-level locking differs based on the condition and operation we are trying to enforce. They are two most commonly used types of row-level locking, namely:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Shared Lock (S Lock)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;S-lock allows multiple transactions to read a row but prevents any from writing to it and is useful in cases when transactions only need to read data without making any modification. For example, multiple users can view the same data row, but none can update it until the shared lock is released.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Exclusive Lock (X Lock)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;X lock is used to prevent any other transaction from reading or writing to the locked row and usually comes into play when a transaction needs to both read and write to a row, ensuring that no other transaction can modify the row until the lock is released. In my case, when a user is requesting to generate an API key, an exclusive lock ensures that the row can't be accessed by another request until the operation is complete.&lt;/p&gt;

&lt;p&gt;Other types of row locking include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update Lock&lt;/li&gt;
&lt;li&gt;Intent Lock&lt;/li&gt;
&lt;li&gt;Key-Range Lock&lt;/li&gt;
&lt;li&gt;Deadlock Avoidance Locks&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Pitfalls of Row-level locking
&lt;/h2&gt;

&lt;p&gt;While row-level locking provides fine-grained control and helps maintain high concurrency, it comes with trade-offs, some of which are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Deadlocks&lt;br&gt;
Deadlocks happen when two or more transactions are waiting for each other to release locks, which causes a circular wait that cannot be resolved without intervention (e.g., transaction rollbacks). Due to many row-level locks being held by different transactions, the likelihood of deadlocks increases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Increased Overhead&lt;br&gt;
When managing row-level locks, it often requires more system resources (memory and CPU) than table-level or page-level locks, because the database needs to track each individual row being locked, which can become resource-intensive, especially with high-concurrency environments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Potential for Lock Escalation&lt;br&gt;
In some databases, if a transaction locks too many rows, the database system might escalate the row-level locks to page-level or even table-level locks to conserve resources which leads to the blocking of other transactions that should have only been blocked on specific rows. Lock escalation can reduce concurrency and cause performance issues in some cases.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Implementation of Row-level locking
&lt;/h2&gt;

&lt;p&gt;Imagine you have a banking app where users can transfer money between accounts. Without row-level locking, two concurrent requests could lead to incorrect balances (e.g., both transactions reading the same balance before updating it, which would cause the account to become overdrawn).&lt;/p&gt;

&lt;p&gt;We'll implement row-level locking with Django Rest Framework &lt;code&gt;transaction&lt;/code&gt; module and &lt;code&gt;select_for_update()&lt;/code&gt; ORM method in other to lock the user account row while updating balances.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After having set up your DRF(Django Rest Framework) project.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Firstly, we'll create the schema for our database table, named Account, with three columns to carry the owner of the account, and the balance in the account.&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Account&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;user&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth.User&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;balance&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;DecimalField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_digits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decimal_places&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Account of &lt;/span&gt;&lt;span class="si"&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;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; with balance &lt;/span&gt;&lt;span class="si"&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;balance&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Serializer:&lt;/strong&gt;&lt;br&gt;
Then we will setup our serializer to handle three fields that will be passed along with the request.&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="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;Account&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TransferSerializer&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;Serializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;from_account_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;to_account_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DecimalField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_digits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decimal_places&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&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;validate_amount&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;value&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;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Transfer amount must be greater than zero.&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;value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;After we have our models in place, our view should look like the below snippet. Here we utilize the &lt;code&gt;transaction&lt;/code&gt; module and DRFs &lt;code&gt;select_for_update()&lt;/code&gt; ORM method.&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="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;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rest_framework.response&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;transaction&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;Account&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;TransferSerializer&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InsufficientFundsException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Custom exception for insufficient funds.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TransferFundsView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;APIView&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;post&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&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="n"&gt;serializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TransferSerializer&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="n"&gt;request&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;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="n"&gt;raise_exception&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;from_account_id&lt;/span&gt; &lt;span class="o"&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;from_account_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;to_account_id&lt;/span&gt; &lt;span class="o"&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;to_account_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;amount&lt;/span&gt; &lt;span class="o"&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;# Perform the transfer inside a transaction with row-level locking
&lt;/span&gt;        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;atomic&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="c1"&gt;# Lock the rows for both the sender's and receiver's accounts
&lt;/span&gt;            &lt;span class="n"&gt;from_account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Account&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;select_for_update&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="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;from_account_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;to_account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Account&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;select_for_update&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="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;to_account_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;# Check if the sender has sufficient balance
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;from_account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;amount&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;InsufficientFundsException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Insufficient funds in the sender&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s account.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;# Perform the transfer by deducting from sender and adding to receiver
&lt;/span&gt;            &lt;span class="n"&gt;from_account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
            &lt;span class="n"&gt;to_account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;

            &lt;span class="c1"&gt;# Save both account updates
&lt;/span&gt;            &lt;span class="n"&gt;from_account&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="n"&gt;to_account&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="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;status&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;success&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;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Transferred &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; successfully&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;status&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_200_OK&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;handle_exception&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;exc&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Handle custom exceptions.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&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="n"&gt;InsufficientFundsException&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;detail&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&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="n"&gt;status&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_400_BAD_REQUEST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&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;handle_exception&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  My Advice
&lt;/h2&gt;

&lt;p&gt;Before you utilize any form of data locking, know what you're doing and take into consideration multiple edge cases.&lt;/p&gt;



&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=nuBi2XbHH18" rel="noopener noreferrer"&gt;Row-level database locks explained by Hussein Nasser&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/sql/relational-databases/sql-server-deadlocks-guide?view=sql-server-ver16" rel="noopener noreferrer"&gt;Understanding deadlocks by Microsoft&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=wEsPL50Uiyo" rel="noopener noreferrer"&gt;Understanding database concurrency control and race conditions&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect with me on:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/stephen-nwankwo-9876b4196/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/Sage_Sten" rel="noopener noreferrer"&gt;X(Twitter)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/stenwire" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>webdev</category>
      <category>backenddevelopment</category>
      <category>python</category>
    </item>
    <item>
      <title>Understanding the Basics of Optimization Loops in PyTorch</title>
      <dc:creator>Stephen Nwankwo</dc:creator>
      <pubDate>Wed, 25 Sep 2024 11:45:38 +0000</pubDate>
      <link>https://forem.com/sten/understanding-the-basics-of-optimization-loops-in-pytorch-10eg</link>
      <guid>https://forem.com/sten/understanding-the-basics-of-optimization-loops-in-pytorch-10eg</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;cover image was generated with google's gemini.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;PyTorch is a powerful, easy-to-use Python deep learning library, mainly used in areas of computer vision and natural language processing, two areas I have a huge interest in. With this article, I hope to help you understand the usage of optimization loops in PyTorch.&lt;/p&gt;

&lt;p&gt;When creating a model, we typically divide the dataset into three parts: one for training, which carries a majority of the data, the second for evaluation, and the last for testing/inference. However, in some cases, we only need just the training set and testing set, depending on the project specification. After obtaining these sets, they undergo a series of operations with the goal of minimizing discrepancies between predictions and actual outcomes.&lt;/p&gt;

&lt;p&gt;With this foundation, we can determine the loss function used to compute the loss value, followed by the optimizer. Both of which are vital for the optimization loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the optimization loop?
&lt;/h2&gt;

&lt;p&gt;The optimization loop is an operation that involves performing two loops, the training loop; an operation that involves learning the relationships or patterns between the internal parameters by passing the training data through the model, and the testing loop, which involves passing the testing data through the trained model and evaluating how good the patterns are that the model learned on the training data. These processes, as the title of this article suggests are called "loops" because we want our model to look (loop through) at each sample in each dataset.&lt;/p&gt;

&lt;p&gt;We now have a basic understanding of what the training and testing loops are, but how do we achieve them? There are a few steps involved in each of these processes, with the test loop containing fewer steps for reasons we will see later on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps involved in the training loop:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Forward pass: here, we initiate a function that performs a one-time calculation as all of the training dataset is passed through the model at once.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Loss value: using the loss function obtained earlier, compare the training set with the predictions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Zero gradient: set the gradients of the model parameters to zero, so they can be updated in the following steps.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Backpropagation: during the loop, a number of model parameters to be updated were obtained, now we have to go back and compute the gradient of the loss using those parameters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Optimizer step: After performing the backpropagation and obtaining the loss gradients, we can then go on to update the model parameters using those results.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To help visualize what this might look like, take a look at Figure 1 below, which is an overview of what the training loop could look like in code. It won't always look like this, it is dependent on the project.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Figure 1: PyTorch training loop &lt;a href="https://www.learnpytorch.io/01_pytorch_workflow/" rel="noopener noreferrer"&gt;[image source]&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Steps involved in the testing loop:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Forward pass: same as in step 1 above, except this time we use the test dataset.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Loss value: compute the loss value in the same manner as in the training loop, using test data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Other evaluation computations: we often need to obtain other metrics to evaluate our model better, some of which are accuracy, precision, recall, F1, etc.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You may have noticed that the testing loop omits the backpropagation and optimizer step. This is because no model parameters are altered during testing; instead, they have already been determined. We are solely interested in the output of the forward run through the model for testing purposes. The annotated image(Figure 2) below illustrates the steps involved in the testing loop.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Figure 2: pytorch testing loop&lt;a href="https://www.learnpytorch.io/01_pytorch_workflow/" rel="noopener noreferrer"&gt;[image source]&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Code example
&lt;/h2&gt;

&lt;p&gt;If we added our understanding of the training loop and testing loop, below is what our optimization loop would look like in a basic project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;link to code:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/stenwire/playground/blob/main/pytorch/01_pytorch_workflow_exercises.ipynb" rel="noopener noreferrer"&gt;https://github.com/stenwire/playground/blob/main/pytorch/01_pytorch_workflow_exercises.ipynb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;code snippet:&lt;/strong&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="c1"&gt;# Optimization loop
&lt;/span&gt;
&lt;span class="c1"&gt;# Train model for 300 epochs
&lt;/span&gt;&lt;span class="n"&gt;epochs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;

&lt;span class="c1"&gt;# Send data to target device
&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;y_train&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;X_test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;y_test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y_test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&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;epoch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;epochs&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&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="c1"&gt;### Perform testing every 20 epochs
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

      &lt;span class="c1"&gt;# Put model in evaluation mode and setup inference context 
&lt;/span&gt;      &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="c1"&gt;# 1. Forward pass
&lt;/span&gt;      &lt;span class="n"&gt;test_pred&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="c1"&gt;# 2. Calculate test loss
&lt;/span&gt;      &lt;span class="n"&gt;test_loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loss_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_pred&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_test&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;train&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
      &lt;span class="c1"&gt;### Training
&lt;/span&gt;
      &lt;span class="c1"&gt;# Put model in train mode
&lt;/span&gt;      &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;train&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

      &lt;span class="c1"&gt;# 1. Forward pass
&lt;/span&gt;      &lt;span class="n"&gt;y_pred&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;# 2. Calculate loss
&lt;/span&gt;      &lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loss_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_pred&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;# 3. Zero gradients
&lt;/span&gt;      &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zero_grad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

      &lt;span class="c1"&gt;# 4. Backpropagation
&lt;/span&gt;      &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

      &lt;span class="c1"&gt;# 5. Step the optimizer
&lt;/span&gt;      &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code sample covers a PyTorch model that learns the pattern of a straight line and matches it, I would love to see other use cases, so feel free to reach out to me on any of the social platforms I added below, let's learn together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connect with me on LinkedIn:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/stephen-nwankwo-9876b4196/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/stephen-nwankwo-9876b4196/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connect with me on X(Twitter):&lt;/strong&gt; &lt;a href="https://x.com/Sage_Sten" rel="noopener noreferrer"&gt;https://x.com/Sage_Sten&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checkout my Github:&lt;/strong&gt; &lt;a href="https://github.com/stenwire" rel="noopener noreferrer"&gt;https://github.com/stenwire&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://www.learnpytorch.io/01_pytorch_workflow/" rel="noopener noreferrer"&gt;https://www.learnpytorch.io/01_pytorch_workflow/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.dataquest.io/blog/pytorch-for-beginners/" rel="noopener noreferrer"&gt;https://www.dataquest.io/blog/pytorch-for-beginners/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>ai</category>
    </item>
    <item>
      <title>OpenAI engineers have cooked once more.</title>
      <dc:creator>Stephen Nwankwo</dc:creator>
      <pubDate>Fri, 16 Feb 2024 00:14:03 +0000</pubDate>
      <link>https://forem.com/sten/openai-engineers-have-cooked-once-more-k8c</link>
      <guid>https://forem.com/sten/openai-engineers-have-cooked-once-more-k8c</guid>
      <description>&lt;p&gt;If you think ChatGPT was revolutionary, get ready to get your mind blown.&lt;/p&gt;

&lt;p&gt;Remember the ruckus between openAI's Sam Altman and OpenAI, that was one occasion that placed OpenAI in the headlines for the wrong reasons. Did you happen to hear the gist? I wrote about it, check it out here. Back to the main topic, OpenAI is here once more with something new, different, original, and revolutionary. I know I sound like an excited fanboy right now, truth is I really am excited, perhaps you've seen a couple of deep fake videos, with the camera fixed in one position and a couple of realistic facial features and ear, eye and mouth movement, this is way more than that.&lt;/p&gt;

&lt;p&gt;OpenAi has just given us an insight into a new AI they've been working on, an AI that generates a 60-second-long video from user prompts. Here's why it is worth the hype, to name a few:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Hyper-realistic characters&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hyper-realistic motion/movement of different characters and objects/particles &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hyper-realistic lightning&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hyper-realistic camera movements&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hyper-realistic character emotions&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You tell me, what makes an amazing video if not all of the above listed, let's all remember we're talking about AI-generated video here, the characters, motion, and lightning look like something straight out of Unreal Engine 5 on steroids, being run on Microsoft supercomputer, it's that amazing. In case you're still in doubt, check the below screenshots from videos created by Sora(name of AI).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpf2vl62or2tc5xbdqivp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpf2vl62or2tc5xbdqivp.png" alt="Prompt: A beautiful homemade video showing the people of Lagos, Nigeria in the year 2056. Shot with a mobile phone camera." width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prompt: A beautiful homemade video showing the people of Lagos, Nigeria in the year 2056. Shot with a mobile phone camera.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi1ivwwiijolyoz02445d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi1ivwwiijolyoz02445d.png" alt="Prompt: A stylish woman walks down a Tokyo street filled with warm glowing neon and animated city signage. She wears a black leather jacket, a long red dress, and black boots, and carries a black purse. She wears sunglasses and red lipstick. She walks confidently and casually. The street is damp and reflective, creating a mirror effect of the colorful lights. Many pedestrians walk about." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prompt: A stylish woman walks down a Tokyo street filled with warm glowing neon and animated city signage. She wears a black leather jacket, a long red dress, and black boots, and carries a black purse. She wears sunglasses and red lipstick. She walks confidently and casually. The street is damp and reflective, creating a mirror effect of the colorful lights. Many pedestrians walk about.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydkwy6b3lxmftvu4ettn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydkwy6b3lxmftvu4ettn.png" alt="Prompt: Aerial view of Santorini during the blue hour, showcasing the stunning architecture of white Cycladic buildings with blue domes. The caldera views are breathtaking, and the lighting creates a beautiful, serene atmosphere." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prompt: Aerial view of Santorini during the blue hour, showcasing the stunning architecture of white Cycladic buildings with blue domes. The caldera views are breathtaking, and the lighting creates a beautiful, serene atmosphere.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, I can't attach a video without hosting it on sites like YouTube or Vimeo, These screenshots are but an abstraction of the divinity created by the company; OpenAI.&lt;/p&gt;

&lt;p&gt;The purpose of this post is to get you excited, I hope you are, and get ready, for openAI engineers are still cooking, and this is nothing compared to what is to come.&lt;/p&gt;

&lt;p&gt;Read more about Sora here: link to Sora&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;References:&lt;/strong&gt;&lt;br&gt;
Cover image by LinkedIn AI&lt;br&gt;
Screenshot from the official Sora page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;About Me:&lt;/strong&gt;&lt;br&gt;
I am a passionate engineer, with 3 years of experience building solutions and products around the web and AI. Checkout my profile: &lt;a href="https://www.linkedin.com/in/stephen-nwankwo-9876b4196" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/stephen-nwankwo-9876b4196&lt;/a&gt;&lt;/p&gt;

</description>
      <category>openai</category>
      <category>ai</category>
      <category>generativeai</category>
    </item>
    <item>
      <title>The Saga of Sam Altman and OpenAI: The story of a controversial ouster and its aftermath.</title>
      <dc:creator>Stephen Nwankwo</dc:creator>
      <pubDate>Tue, 21 Nov 2023 13:36:45 +0000</pubDate>
      <link>https://forem.com/sten/the-saga-of-sam-altman-and-openai-the-story-of-a-controversial-ouster-and-its-aftermath-i54</link>
      <guid>https://forem.com/sten/the-saga-of-sam-altman-and-openai-the-story-of-a-controversial-ouster-and-its-aftermath-i54</guid>
      <description>&lt;p&gt;Perhaps, you have not paid attention to the events with OpenAI and Sam Altman that has happened recently, or maybe you need clearity. Let me share with you what happened this weekend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who is Sam Altman?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sam Altman is one of the prominent people in the tech market who co-founded OpenAI and served as president of Y-combinator between 2014-2019. He now leads another team in applied AI research department at Microsoft(more on this later on).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Unexpected Layoff&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On Friday November 17, 2023; OpenAI made a strange move. The firm renowned for its consideration toward AI ethics and safety terminated Sam Altman who is the most passionate supporter of AIs positive impacts on humanity.&lt;/p&gt;

&lt;p&gt;This move surprised and disappointed a lot of people as it was brought about by a resolution passed by a board meeting of OpenAIs directors. It also had its intriguing aspect as very few people knew about the identity of most of the members of the board.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Reason Behind the Layoff&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The board made that decision with the claim that it had lost confidence in Sam Altman’s communication style. Some said that he had failed to be “honest” with the board, thus, it was difficult for them to perform their duties as members of the board.&lt;/p&gt;

&lt;p&gt;The confusion was further compounded by the fact that the OpenAI investors were allegedly not informed of the activities and projects carried out at the company. However, it could not be determined with certainty what exactly was the cause of Altman’s failure in communication; it was most likely, though, the reason behind was a deficiency of openness.&lt;/p&gt;

&lt;p&gt;During these speculations one Reddit user under the user name Anxious_Bandicoot126 offered a more detailed explanation behind the firing of Altman. Altman has been laid-off due to his focus on profits. They also went on to say that Altman prematurely released tech without proper safety assessment for the sake of fame and fortune rather than considering the company’s core values.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Attempted Reconciliation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After the strong protests from many parties, even from distinguished experts in technology, the OpenAI board somehow comprehended the magnitude of their choice. The board tried to have the layoff rescinded and brought Sam Altman back to the business.&lt;/p&gt;

&lt;p&gt;A little bit of history repeated itself with some irony in this instance, as it bore a striking resemblance to another such event that took place in years past involving Apple and Steve Jobs.&lt;/p&gt;

&lt;p&gt;At first, it seemed like Altman could return since he believed totally in the goals set for OpenAI. He, however, stipulated that he should only go back after the current OpenAi Board had been completely purged.&lt;/p&gt;

&lt;p&gt;However, negotiations collapsed as Open AI refused to accept the condition proposed by Sam Altman.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Ripple Effect&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Altman’s layoff had far-reaching effects that went beyond the boardroom. Moreover, OpenAI received a lot of criticism from the public, thus losing several important executives namely Greg Brockman and Ilya Sutskever who publicly opposed the action.&lt;/p&gt;

&lt;p&gt;An ill-fated layoff saw Ilya Sutskever, one of their board members publicly apologies as well as promise re-unification with the company. However, Greg Brockman reacted saying that he was in great shock with the news but will work towards discovering what happened.&lt;/p&gt;

&lt;p&gt;Financial implications have been seen in the loss of billions of dollars in the company’s secondary share, and a foreseen 90% drop in valuation in 2024.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Aftermath and Next Steps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At present, only the names of Sam Altman and Greg Brockman could be mentioned from among several colleagues who just entered into the “Advanced AI research team” of Microsoft, whereas other representatives may take the decision to resign from OpenAI and join Altman.&lt;/p&gt;

&lt;p&gt;The present CEO of OpenAI is Emmett Shear (major shareholder in Anthropic – OpenAI’s foremost competitor). He considers a possibility for combining Anthropic with OpenAI, the leading competing organization. Nevertheless, signs of trouble in negotiations have been evident.&lt;/p&gt;

&lt;p&gt;Personally, I think that the first thing that OpenAI must do is take care of the uneasiness inside the company. It is imperative for OpenAI to move with speed following employee dissatisfaction and other companies like Salesforce making attractive offers so as to ensure the firm’s internal morale and stability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenAI's Justified Actions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The question remains: WAS SAM ALTMAN JUSTIFIED TO BE FIRED BY OPENAI? It is a multifaceted and complicated response.&lt;/p&gt;

&lt;p&gt;Communication is of utmost importance towards building an ethics-oriented company and therefore the necessity of clearly defined policies in place is critical.&lt;/p&gt;

&lt;p&gt;On the other hand, Altman's contributions to OpenAI and his unwavering commitment to AI's positive impact on humanity are undeniable.His dismissal is bound to have a great effect on the company and the tech community in general. This decision by openAI raises questions on their leadership and value system. Although the realities of the matter still are not known, there is no doubt that this would cast a shadow on OpenAI’s future.&lt;/p&gt;

&lt;p&gt;Is OpenAI action justified? What do you think?&lt;/p&gt;

&lt;p&gt;🙋♂️ 𝑰'𝒎 𝒂 𝒔𝒐𝒇𝒕𝒘𝒂𝒓𝒆 𝒆𝒏𝒈𝒊𝒏𝒆𝒆𝒓 𝒘𝒊𝒕𝒉 𝒊𝒏𝒕𝒆𝒓𝒆𝒔𝒕 𝒊𝒏 𝑨𝑰, 𝙨𝙤𝙛𝙩𝙬𝙖𝙧𝙚 𝒅𝒆𝒗𝒆𝒍𝒐𝒑𝒎𝒆𝒏𝒕, 𝒂𝒏𝒅 𝒓𝒐𝒃𝒐𝒕𝒊𝒄𝒔.&lt;/p&gt;

&lt;p&gt;𝑭𝒐𝒍𝒍𝒐𝒘 𝒎𝒆 𝒐𝒏 𝑳𝒊𝒏𝒌𝒆𝒅𝑰𝒏: &lt;a href="https://www.linkedin.com/in/stephen-nwankwo-9876b4196" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/stephen-nwankwo-9876b4196&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>openai</category>
      <category>chatgpt</category>
    </item>
    <item>
      <title>HATEOAS Principle - Generating Full Paths for Objects in Django Rest Framework.</title>
      <dc:creator>Stephen Nwankwo</dc:creator>
      <pubDate>Wed, 28 Jun 2023 16:48:55 +0000</pubDate>
      <link>https://forem.com/sten/hateoas-principle-generating-full-paths-for-objects-in-django-rest-framework-366j</link>
      <guid>https://forem.com/sten/hateoas-principle-generating-full-paths-for-objects-in-django-rest-framework-366j</guid>
      <description>&lt;p&gt;&lt;strong&gt;Back-story:&lt;/strong&gt; Pssft - Please move closer.&lt;br&gt;
So I'm in this particular developers WhatsApp group, where various topics are discussed, and pair-debugging is carried out, amongst other things. Most precious of them all are the infos that are shared - from job openings to latest frameworks and best practices.&lt;br&gt;
On a accursed day, a link was shared. It was a link to a blog post by MIcrosoft, its title was "RESTful web API design". I decided to read through and I came across a concept, which is "HATEOAS"(chill! more info later on). I could have sworn I have seen it somewhere before, but I have never really considered it until now. Fast-forward, it tingled my fancy ;) So I decided to try to implement it using Django Rest Framework(DRF) and I will be showing you how.&lt;/p&gt;

&lt;p&gt;--------------- But firstly, here's what I learned about HATEOAS:&lt;/p&gt;
&lt;h2&gt;
  
  
  What is HATEOAS principle?
&lt;/h2&gt;

&lt;p&gt;HATEOAS (Hypermedia as the Engine of Application State) is a principle in API design that aims to make APIs more discoverable and self-descriptive. In the simplest terms, it means that an API response should include links or references to related resources and actions that can be performed.&lt;/p&gt;

&lt;p&gt;Imagine you're browsing a website and you come across a product page. On that page, you not only see information about the product but also links to related actions like "Add to Cart," "View Reviews," or "Similar Products." These links provide you with a way to navigate the website without having to manually construct URLs or know the entire structure of the website beforehand.&lt;/p&gt;

&lt;p&gt;HATEOAS applies the same concept to APIs. Instead of just receiving data in an API response, the response also contains links or references to related resources or actions. These links can guide you on how to interact with the API and discover other relevant information. For example, if you receive data about a particular user, the response may include links to update their profile, retrieve their orders, or view their followers.&lt;/p&gt;

&lt;p&gt;By including these links in the API responses, clients consuming the API can navigate and interact with the API more easily. They don't need to rely on prior knowledge or hard-coded URLs but can follow the links provided by the API to access different resources or perform actions.&lt;/p&gt;

&lt;p&gt;In summary, HATEOAS simplifies API usage by including links or references within API responses, allowing clients to navigate and interact with the API more dynamically and discover its capabilities without extensive prior knowledge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enough talk, Here's what a HATEOAS response looks like:&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;In this example, we have a response for a book resource. The response includes the book's ID, title, and the author's information. The author is represented as a nested object, including their ID and name. Additionally, both the book and the author objects contain a "links" field.&lt;/p&gt;

&lt;p&gt;The "links" field within the book object provides references to related resources and actions. In this case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The "self" link points to the URL for the book resource itself:&lt;br&gt;
"&lt;a href="https://api.example.com/books/1" rel="noopener noreferrer"&gt;https://api.example.com/books/1&lt;/a&gt;".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The "reviews" link points to the URL where the client can access the reviews for the book: "&lt;a href="https://api.example.com/books/1/reviews" rel="noopener noreferrer"&gt;https://api.example.com/books/1/reviews&lt;/a&gt;".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The "similar_books" link points to the URL where the client can find a list of similar books: "&lt;a href="https://api.example.com/books/1/similar" rel="noopener noreferrer"&gt;https://api.example.com/books/1/similar&lt;/a&gt;".&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Similarly, the "links" field within the author object includes a "self" link, which provides the URL for the author's resource: "&lt;a href="https://api.example.com/authors/1" rel="noopener noreferrer"&gt;https://api.example.com/authors/1&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;These links allow clients to navigate the API by following the provided URLs, without needing to construct them manually or have prior knowledge of the API's structure. Clients can easily access related resources like reviews or find similar books by simply following the appropriate links in the API response.&lt;/p&gt;


&lt;h2&gt;
  
  
  Basic Implementation in DRF
&lt;/h2&gt;

&lt;p&gt;The implementation here is rather quick and easy, but might not always be the case depending on project scale.&lt;/p&gt;

&lt;p&gt;I would assume you already have knowledge in python, Django and REST, so I won't be talking about all the nitty-gritty of things, only when needed.&lt;/p&gt;

&lt;p&gt;Now we know what HATEOAS is mostly about - which is attaching hypermedia or resource links to your API json response. With this article I will be showing you a simple approach to creating such link/path.&lt;/p&gt;

&lt;p&gt;Requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.python.org/downloads/" rel="noopener noreferrer"&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.djangoproject.com/en/4.2/topics/install/" rel="noopener noreferrer"&gt;Django&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/" rel="noopener noreferrer"&gt;setup and activate virtual environment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;-- setup virtual environment(for windows):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;project_folder

&lt;span class="nv"&gt;$&amp;gt;&lt;/span&gt; pip &lt;span class="nb"&gt;install &lt;/span&gt;virtualenv

&lt;span class="nv"&gt;$&amp;gt;&lt;/span&gt; python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv

&lt;span class="nv"&gt;$&amp;gt;&lt;/span&gt; .&lt;span class="se"&gt;\v&lt;/span&gt;&lt;span class="nb"&gt;env&lt;/span&gt;&lt;span class="se"&gt;\S&lt;/span&gt;cripts&lt;span class="se"&gt;\a&lt;/span&gt;ctivate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set up a Django project:&lt;br&gt;
 Create a new Django project by running the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   pip &lt;span class="nb"&gt;install &lt;/span&gt;django

   pip &lt;span class="nb"&gt;install &lt;/span&gt;djangorestframework

   django-admin startproject library_project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new Django app:&lt;br&gt;
 Navigate to the project directory and create a new Django app, which will handle the logic for books and authors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;cd &lt;/span&gt;library_project
   python manage.py startapp library
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Define the models: In the &lt;code&gt;library/models.py&lt;/code&gt; file, define the models for books and authors. For example:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Author&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;name&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;100&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;name&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_absolute_url&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/authors/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Book&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;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;author&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;Author&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="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;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_absolute_url&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/books/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Create serializers: In the &lt;code&gt;library/serializers.py&lt;/code&gt; file, create serializers for the models defined earlier. Include the &lt;code&gt;SerializerMethodField&lt;/code&gt; to generate the full path for the &lt;code&gt;id&lt;/code&gt; field.&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="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;library.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthorSerializer&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="n"&gt;detail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SerializerMethodField&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_detail&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;obj&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;request&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;context&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;request&lt;/span&gt;&lt;span class="sh"&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;request&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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build_absolute_uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_absolute_url&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;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&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;Author&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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookSerializer&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="n"&gt;detail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SerializerMethodField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AuthorSerializer&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_detail&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;obj&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;request&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;context&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;request&lt;/span&gt;&lt;span class="sh"&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;request&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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build_absolute_uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_absolute_url&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;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&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;Book&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Define URLs: In the &lt;code&gt;library/urls.py&lt;/code&gt; file, define the URLs for the API endpoints.&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="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;library.views&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BookListCreateView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BookRetrieveUpdateDestroyView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AuthorListCreateView&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;books/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BookListCreateView&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;book-list-create&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;books/&amp;lt;int: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;BookRetrieveUpdateDestroyView&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;book-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="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;authors/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AuthorListCreateView&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;book-list-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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create views: In the &lt;code&gt;library/views.py&lt;/code&gt; file, create views for handling the API endpoints.&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="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;library.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Author&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;library.serializers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BookSerializer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AuthorSerializer&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookListCreateView&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;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Book&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="n"&gt;serializer_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BookSerializer&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookRetrieveUpdateDestroyView&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;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Book&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="n"&gt;serializer_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BookSerializer&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthorListCreateView&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;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Author&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="n"&gt;serializer_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AuthorSerializer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Include the app in the project settings: In the &lt;code&gt;library_project/settings.py&lt;/code&gt; file, include the &lt;code&gt;library&lt;/code&gt; app and configure the REST framework.&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="c1"&gt;# Other apps...
&lt;/span&gt;       &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;library&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;rest_framework&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="n"&gt;REST_FRAMEWORK&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;DEFAULT_RENDERER_CLASSES&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rest_framework.renderers.JSONRenderer&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;Include a link to the app urls in the project urlr.py file: In the &lt;code&gt;library_project/urls.py&lt;/code&gt; file, include:&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="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="c1"&gt;# import 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="c1"&gt;# include the library app urls module
&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="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;library.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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run migrations: Apply the database migrations to create the necessary tables for the models:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Start the development server: Launch the development server to test the API:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Here's what the request and response will look like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Request:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="s1"&gt;'http://127.0.0.1:8000/books/'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"id"&lt;/span&gt;: 1,
        &lt;span class="s2"&gt;"detail"&lt;/span&gt;: &lt;span class="s2"&gt;"http://127.0.0.1:8000/books/1/"&lt;/span&gt;,
        &lt;span class="s2"&gt;"author"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"id"&lt;/span&gt;: 1,
            &lt;span class="s2"&gt;"detail"&lt;/span&gt;: &lt;span class="s2"&gt;"http://127.0.0.1:8000/authors/1/"&lt;/span&gt;,
            &lt;span class="s2"&gt;"name"&lt;/span&gt;: &lt;span class="s2"&gt;"Stephen Nwankwo"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="s2"&gt;"title"&lt;/span&gt;: &lt;span class="s2"&gt;"Tales of Ogun"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"id"&lt;/span&gt;: 2,
        &lt;span class="s2"&gt;"detail"&lt;/span&gt;: &lt;span class="s2"&gt;"http://127.0.0.1:8000/books/2/"&lt;/span&gt;,
        &lt;span class="s2"&gt;"author"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"id"&lt;/span&gt;: 1,
            &lt;span class="s2"&gt;"detail"&lt;/span&gt;: &lt;span class="s2"&gt;"http://127.0.0.1:8000/authors/1/"&lt;/span&gt;,
            &lt;span class="s2"&gt;"name"&lt;/span&gt;: &lt;span class="s2"&gt;"Stephen Nwankwo"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="s2"&gt;"title"&lt;/span&gt;: &lt;span class="s2"&gt;"Tales of Ogun"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Do we really need HATEOAS?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fax92yw4hoaog904cjgbw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fax92yw4hoaog904cjgbw.png" alt="Why you may need to implement HATEOAS" width="400" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have browsed through a number of APIs, and didn't actually come across HATEOS implementation. So on the issue of whether one needs it or not is really up to you the developer or project manager.&lt;/p&gt;

&lt;p&gt;To help you make that decision, depending on the specific requirements and goals of your project. Here are a few points to consider:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Enhanced discoverability: HATEOAS provides a self-descriptive nature to APIs, allowing clients to discover and navigate the available resources dynamically. It eliminates the need for clients to rely on prior knowledge or hard-coded URLs, making the API more intuitive and easier to use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reduced coupling: By including links or references to related resources in API responses, HATEOAS reduces the coupling between clients and servers. Clients can follow the provided links to access different resources and perform actions without needing to know the entire API structure in advance. This promotes loose coupling and enables more flexible and extensible systems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improved scalability: HATEOAS enables the server to evolve and add new resources or actions without breaking existing clients. Clients that follow links provided in API responses can adapt to changes in the API without requiring modifications to their code. This makes the API more scalable and facilitates versioning and backward compatibility.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Client development simplicity: HATEOAS simplifies client development by providing a guided approach to API interaction. Clients can rely on the links provided in the API responses instead of constructing URLs manually or hard-coding them. This reduces the complexity and potential errors in client code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consistency and documentation: HATEOAS promotes consistency and provides a form of self-documentation within the API itself. The links included in the responses serve as a reference to the available actions and resources, making it easier for developers to understand and utilize the API effectively.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;However, it's important to note that implementing HATEOAS adds complexity to the API design and development process. It requires careful consideration of the links to include, balancing between providing enough information and avoiding overwhelming clients with excessive links. Additionally, HATEOAS may not be necessary or appropriate for all API use cases, especially when the API's scope is small or the client-server interaction is straightforward.&lt;/p&gt;

&lt;p&gt;Ultimately, the decision to use HATEOAS should be based on factors such as the complexity of your API, the desired level of discoverability and flexibility, and the needs of your clients.&lt;/p&gt;




&lt;p&gt;Please leave a like if you found the article useful, also feel free to share your opinions in the comment section.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/architecture/best-practices/api-design" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/azure/architecture/best-practices/api-design&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.geeksforgeeks.org/hateoas-and-why-its-needed-in-restful-api/" rel="noopener noreferrer"&gt;https://www.geeksforgeeks.org/hateoas-and-why-its-needed-in-restful-api/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.w3schools.in/restful-web-services/rest-apis-hateoas-concept#google_vignette" rel="noopener noreferrer"&gt;https://www.w3schools.in/restful-web-services/rest-apis-hateoas-concept#google_vignette&lt;/a&gt;&lt;/p&gt;

</description>
      <category>django</category>
      <category>api</category>
      <category>rest</category>
      <category>drf</category>
    </item>
    <item>
      <title>CPU and GPU...like I'm 5</title>
      <dc:creator>Stephen Nwankwo</dc:creator>
      <pubDate>Wed, 06 Apr 2022 21:38:36 +0000</pubDate>
      <link>https://forem.com/sten/cpu-and-gpulike-im-5-4jj1</link>
      <guid>https://forem.com/sten/cpu-and-gpulike-im-5-4jj1</guid>
      <description>&lt;p&gt;I will stray away from the technical aspects as I intend to make this as basic as possible.&lt;/p&gt;

&lt;p&gt;A computer is a lot like an earth person. The two most important components of the human being are the Heart and the brain. The computer also possesses just like humans its own heart and brain and that is what we'll be learning about today.&lt;/p&gt;

&lt;p&gt;Welcome to computational biology 101...(coined that up right now)&lt;/p&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the CPU?
&lt;/h2&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsvm4cq5viyd1afe2eonr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsvm4cq5viyd1afe2eonr.jpg" alt="GPU" width="800" height="449"&gt;&lt;/a&gt;&lt;br&gt;
We all know the CPU, the central processing unit to be the brain of the computer as we were told in grade five, and that is essentially what a CPU is. A CPU is capable of handling all of the affairs of the computer ranging from writing documents, listening to music, watching videos, and being a nuisance on our favorite social media.&lt;/p&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the GPU?
&lt;/h2&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnwu26kaleesj70au9jkm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnwu26kaleesj70au9jkm.jpg" alt="GPU" width="800" height="600"&gt;&lt;/a&gt;&lt;br&gt;
GPU stands for Graphics Processing Unit... I like to refer to GPU as the heart of the computer. Just like in human beings where the activities performed by the heart are completely independent of the brain, the same goes for the GPU.&lt;br&gt;
The primary activity performed by the heart is the pumping of blood to the brain and the rest of the body, which we all know is a vital activity for the sustenance of an earth person. Just like the heart, the primary purpose of the GPU is to support the CPU in certain areas which will be discussed later on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why have a CPU and a GPU?
&lt;/h2&gt;

&lt;p&gt;As mentioned earlier I will try to stray away from the technical aspects as I intend to make this as basic as possible.&lt;br&gt;
I would like to start with the activities carried out by the CPU.&lt;br&gt;
The CPU controls everything in a computer, some of these common tasks carried out by the CPU includes copying a file from the flash drive to the computer, watching an episode of family guy on your video player, trying to calculate the sum of 67822 and 9370, listening to your favorite artist album, typing a document, joining a meeting online, ... the list goes on.&lt;br&gt;
  Moving on to why you may need a GPU. to go straight to the point, one does not really need a GPU if you don't play any game from 5years ago, you don't do any video editing, 3d modeling, artificial intelligence, etc.&lt;br&gt;
If you happen to be like me, a gamer and a dev. I would advise you to go for a pc with a CPU and a GPU.&lt;br&gt;
To sum it all up, the GPU does the real heavy lifting for the pc and the CPU handles all other affairs that do not require too much graphic processing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not use a standalone GPU?
&lt;/h2&gt;

&lt;p&gt;The reason why no pc should operate only on a GPU is that the GPU as mighty as it may sound can not really handle a lot of activity from different system applications all at the same time as the CPU.&lt;/p&gt;

&lt;p&gt;The major manufacturer of CPUs is Intel and for GPU we have Nvidia and AMD...example of a CPU is the intel 5500 and a GPU is the NVIDIA 3060TI. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;I would leave you with a piece of advice; never buy a PC with a low-grade AMD GPU instead go for a Nvidia 800-series if funding might be an issue.&lt;/em&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;AMD = &lt;a href="https://en.wikipedia.org/wiki/Advanced_Micro_Devices" rel="noopener noreferrer"&gt;Advanced Micro Devices, Inc&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GPU = &lt;a href="https://en.wikipedia.org/wiki/Graphics_processing_unit" rel="noopener noreferrer"&gt;Graphic Processing Unit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Intel: &lt;a href="https://en.wikipedia.org/wiki/Intel" rel="noopener noreferrer"&gt;just Intel :)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;NVIDIA = &lt;a href="https://en.wikipedia.org/wiki/Nvidia" rel="noopener noreferrer"&gt;just NVIDIA :)&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I didn't cover a lot, please use the links above.&lt;/p&gt;

</description>
      <category>cpu</category>
      <category>gpu</category>
      <category>computerscience</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
