{"@attributes":{"version":"2.0"},"channel":{"title":"DEV Community: Kim","description":"The latest articles on DEV Community by Kim (@ki3ani).","link":"https:\/\/dev.to\/ki3ani","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%2F461692%2F1a5bae3f-55f9-4a97-b3a3-b99aec3197c5.jpg","title":"DEV Community: Kim","link":"https:\/\/dev.to\/ki3ani"},"language":"en","item":[{"title":"Building AI Agents with GKE","pubDate":"Mon, 22 Sep 2025 17:21:20 +0000","link":"https:\/\/dev.to\/ki3ani\/building-ai-agents-with-gke-5clk","guid":"https:\/\/dev.to\/ki3ani\/building-ai-agents-with-gke-5clk","description":"<p><em>This article was created as part of my official submission to the GKE Turns 10 Hackathon.<\/em><\/p>\n\n<p>The challenge was simple but profound: take a standard microservices application the Online Boutique and \"supercharge\" it with AI without touching a single line of the original code. The goal was to build an external, containerized \"brain\" that could add a new layer of intelligence.<\/p>\n\n<p>My answer? I built a fully autonomous, multi-agent AI team on Google Kubernetes Engine (GKE). Here's how I did it, and how GKE's features were fundamental to making this complex architecture work.<\/p>\n\n<h2>\n  \n  \n  The Foundation: GKE and Service Discovery\n<\/h2>\n\n<p>The entire project relies on multiple new microservices (agents, servers, UIs) communicating with each other and with the original Online Boutique app. GKE's built-in service discovery made this incredibly simple.<\/p>\n\n<p>By defining a Kubernetes <code>Service<\/code>, I could give each component a stable DNS name. For example, the Marketing Agent's <code>Service<\/code> looks like this:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"na\">apiVersion<\/span><span class=\"pi\">:<\/span> <span class=\"s\">v1<\/span>\n<span class=\"na\">kind<\/span><span class=\"pi\">:<\/span> <span class=\"s\">Service<\/span>\n<span class=\"na\">metadata<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">marketing-campaigner-service<\/span>\n<span class=\"na\">spec<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">selector<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">app<\/span><span class=\"pi\">:<\/span> <span class=\"s\">marketing-campaigner-agent<\/span>\n  <span class=\"na\">ports<\/span><span class=\"pi\">:<\/span>\n  <span class=\"pi\">-<\/span> <span class=\"na\">port<\/span><span class=\"pi\">:<\/span> <span class=\"m\">8080<\/span>\n    <span class=\"na\">targetPort<\/span><span class=\"pi\">:<\/span> <span class=\"m\">8080<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>This simple YAML meant that my Business Analyst agent could reliably send A2A messages just by calling <a href=\"http:\/\/marketing-campaigner-service:8080\/goal\" rel=\"noopener noreferrer\"><code>http:\/\/marketing-campaigner-service:8080\/goal<\/code><\/a>. GKE handled all the complex networking behind the scenes.<\/p>\n\n<h2>\n  \n  \n  The \"Senses\": An MCP Server with a Secure Sidecar\n<\/h2>\n\n<p>The first component I built was an MCP Server to act as the system's \"senses.\" It ingests real-time \"add to cart\" events from the app's <code>frontend-proxy<\/code>. To connect securely to the Cloud SQL database, I used the <strong>Cloud SQL Auth Proxy<\/strong> running as a sidecar container, a best practice made easy by GKE's pod architecture.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code>    <span class=\"na\">spec<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">serviceAccountName<\/span><span class=\"pi\">:<\/span> <span class=\"s\">mcp-toolbox-sa<\/span>\n      <span class=\"na\">containers<\/span><span class=\"pi\">:<\/span>\n      <span class=\"pi\">-<\/span> <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">server<\/span> <span class=\"c1\"># My Python App<\/span>\n        <span class=\"na\">image<\/span><span class=\"pi\">:<\/span> <span class=\"s\">...<\/span>\n        <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n          <span class=\"pi\">-<\/span> <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">DB_HOST<\/span>\n            <span class=\"na\">value<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">127.0.0.1\"<\/span>\n      <span class=\"pi\">-<\/span> <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">cloud-sql-proxy<\/span> <span class=\"c1\"># The Sidecar<\/span>\n        <span class=\"na\">image<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"nv\">gcr.io\/cloud-sql-connectors\/cloud-sql-proxy<\/span><span class=\"pi\">:<\/span><span class=\"nv\">2.8.0<\/span><span class=\"pi\">]<\/span><span class=\"s\">(http:\/\/gcr.io\/cloud-sql-connectors\/cloud-sql-proxy:2.8.0)<\/span>\n        <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">...\"<\/span><span class=\"pi\">]<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  The \"Strategist\": A Scheduled Agent with <code>CronJob<\/code>\n<\/h2>\n\n<p>My Business Analyst agent doesn't need to run 24\/7; it just needs to wake up periodically to check for trends. A GKE <code>CronJob<\/code> was the perfect tool for this. With a simple <code>schedule<\/code> expression, I could define this \"sense-think-act\" loop to run automatically.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"na\">apiVersion<\/span><span class=\"pi\">:<\/span> <span class=\"s\">batch\/v1<\/span>\n<span class=\"na\">kind<\/span><span class=\"pi\">:<\/span> <span class=\"s\">CronJob<\/span>\n<span class=\"na\">metadata<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">business-analyst-agent<\/span>\n<span class=\"na\">spec<\/span><span class=\"pi\">:<\/span>\n  <span class=\"c1\"># Run every 5 minutes<\/span>\n  <span class=\"na\">schedule<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">*\/5<\/span><span class=\"nv\"> <\/span><span class=\"s\">*<\/span><span class=\"nv\"> <\/span><span class=\"s\">*<\/span><span class=\"nv\"> <\/span><span class=\"s\">*<\/span><span class=\"nv\"> <\/span><span class=\"s\">*\"<\/span>\n  <span class=\"na\">jobTemplate<\/span><span class=\"pi\">:<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>After deploying, GKE takes care of the rest, spinning up and shutting down pods on schedule. Watching the pods transition to <code>Completed<\/code> status was proof the autonomous loop was working.<\/p>\n\n<p><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%2Fm34brosuyr3wavcwyrnf.png\" class=\"article-body-image-wrapper\"><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%2Fm34brosuyr3wavcwyrnf.png\" alt=\"pods\" width=\"800\" height=\"352\"><\/a><\/p>\n\n<h2>\n  \n  \n  The \"Executor\": Agent Collaboration via A2A\n<\/h2>\n\n<p>When the Analyst agent finds a trend, it delegates a task to the Marketing agent. This Agent2Agent (A2A) communication is just a simple, decoupled <code>POST<\/code> request, made possible by the GKE <code>Service<\/code> we defined earlier.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code>\n<span class=\"k\">def<\/span> <span class=\"nf\">send_a2a_goal<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">product_name<\/span><span class=\"p\">):<\/span>\n    <span class=\"c1\"># GKE DNS resolves 'marketing-campaigner-service' to the correct pod IP\n<\/span>    <span class=\"p\">[<\/span><span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">marketing<\/span><span class=\"p\">](<\/span><span class=\"n\">http<\/span><span class=\"p\">:<\/span><span class=\"o\">\/\/<\/span><span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">marketing<\/span><span class=\"p\">)<\/span><span class=\"n\">_agent_url<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">http:\/\/marketing-campaigner-service:8080\/goal<\/span><span class=\"sh\">\"<\/span>\n\n    <span class=\"n\">a2a_message<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">goal<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">create_promotional_content<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">payload<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">product_name<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">product_name<\/span> <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n    <span class=\"p\">[<\/span><span class=\"n\">requests<\/span><span class=\"p\">.<\/span><span class=\"n\">post<\/span><span class=\"p\">](<\/span><span class=\"n\">http<\/span><span class=\"p\">:<\/span><span class=\"o\">\/\/<\/span><span class=\"n\">requests<\/span><span class=\"p\">.<\/span><span class=\"n\">post<\/span><span class=\"p\">)([<\/span><span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">marketing<\/span><span class=\"p\">](<\/span><span class=\"n\">http<\/span><span class=\"p\">:<\/span><span class=\"o\">\/\/<\/span><span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">marketing<\/span><span class=\"p\">)<\/span><span class=\"n\">_agent_url<\/span><span class=\"p\">,<\/span> <span class=\"n\">json<\/span><span class=\"o\">=<\/span><span class=\"n\">a2a_message<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The Marketing agent, running in its own <code>Deployment<\/code>, simply listens for these incoming requests and executes its own logic.<\/p>\n\n<h2>\n  \n  \n  Agent 3: The AI Specialist (A2A &amp; MCP Client)\n<\/h2>\n\n<p>This was the most ambitious step. I replaced the original recommendationservice with my own AI-powered Recommendation Agent. This agent is a showcase of advanced agent design, using both A2A collaboration and the MCP pattern. It acts as a gRPC server, and when it receives a request from the frontend:<\/p>\n\n<ul>\n<li>It makes an A2A call to the Marketing agent to ask which product is currently being promoted, demonstrating real-time agent collaboration.<\/li>\n<li>It acts as an MCP Client, using the application's own productcatalogservice as a direct \"tool\" (via gRPC) to get rich, grounded context on the user's cart items.<\/li>\n<li>It uses Gemini to generate intelligent recommendations based on all this combined context.\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># recommendation-agent\/agent.py\n<\/span><span class=\"k\">def<\/span> <span class=\"nf\">ListRecommendations<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">request<\/span><span class=\"p\">,<\/span> <span class=\"n\">context<\/span><span class=\"p\">):<\/span>\n    <span class=\"c1\"># A2A Collaboration: Ask another agent for its state\n<\/span>    <span class=\"n\">promoted_product<\/span> <span class=\"o\">=<\/span> <span class=\"n\">requests<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">MARKETING_AGENT_URL<\/span><span class=\"p\">).<\/span><span class=\"nf\">json<\/span><span class=\"p\">().<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">product_name<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"c1\"># MCP Client Action (Tool Use): Get data from the application\n<\/span>    <span class=\"n\">cart_product_names<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"nf\">get_product_name_from_id<\/span><span class=\"p\">(<\/span><span class=\"n\">pid<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">pid<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">product_ids<\/span><span class=\"p\">]<\/span>\n\n    <span class=\"c1\"># Think with Gemini using the rich context\n<\/span>    <span class=\"n\">prompt<\/span> <span class=\"o\">=<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">User<\/span><span class=\"sh\">'<\/span><span class=\"s\">s Cart: <\/span><span class=\"si\">{<\/span><span class=\"n\">cart_product_names<\/span><span class=\"si\">}<\/span><span class=\"s\">, Promoted Product: <\/span><span class=\"sh\">'<\/span><span class=\"si\">{<\/span><span class=\"n\">promoted_product<\/span><span class=\"si\">}<\/span><span class=\"sh\">'<\/span><span class=\"s\">...<\/span><span class=\"sh\">\"<\/span>\n    <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">model<\/span><span class=\"p\">.<\/span><span class=\"nf\">generate_content<\/span><span class=\"p\">(<\/span><span class=\"n\">prompt<\/span><span class=\"p\">)<\/span>\n    <span class=\"c1\"># ...\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Agent 4: The Conversational Assistant (Grounded MCP Client)\n<\/h2>\n\n<p>To add an interactive element, I built a Customer Support Agent. This agent is a prime example of an MCP Client that is designed to be user-facing and does not use A2A. Its sole focus is to help the user. It uses the application's productcatalogservice as a tool (via gRPC) to get real-time data. Crucially, it is explicitly \"grounded\"\u2014instructed to only answer questions based on the data it retrieves. This prevents the AI from hallucinating and builds user trust.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"n\">final_prompt<\/span> <span class=\"o\">=<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"\"\"<\/span><span class=\"s\">\nAnswer the user<\/span><span class=\"sh\">'<\/span><span class=\"s\">s question based ONLY on the product data provided. Do not make up information.\n\nUser<\/span><span class=\"sh\">'<\/span><span class=\"s\">s Question: <\/span><span class=\"sh\">\"<\/span><span class=\"si\">{<\/span><span class=\"n\">question<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"s\">\nProduct Data: <\/span><span class=\"sh\">\"<\/span><span class=\"si\">{<\/span><span class=\"n\">product_context<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"s\">\n<\/span><span class=\"sh\">\"\"\"<\/span>\n<span class=\"n\">final_response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">model<\/span><span class=\"p\">.<\/span><span class=\"nf\">generate_content<\/span><span class=\"p\">(<\/span><span class=\"n\">final_prompt<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  The \"Wow\" Factor: Public UIs with <code>LoadBalancer<\/code>\n<\/h2>\n\n<p>For the final submission, I needed public URLs for the judges. GKE makes this incredibly simple. By changing one line in my dashboard's <code>Service<\/code> definition to <code>type: LoadBalancer<\/code>, GKE automatically provisioned a public IP address.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"na\">apiVersion<\/span><span class=\"pi\">:<\/span> <span class=\"s\">v1<\/span>\n<span class=\"na\">kind<\/span><span class=\"pi\">:<\/span> <span class=\"s\">Service<\/span>\n<span class=\"na\">metadata<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">dashboard-ui-service<\/span>\n<span class=\"na\">spec<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">LoadBalancer<\/span>\n  <span class=\"na\">selector<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">app<\/span><span class=\"pi\">:<\/span> <span class=\"s\">dashboard-ui<\/span>\n  <span class=\"na\">ports<\/span><span class=\"pi\">:<\/span>\n  <span class=\"pi\">-<\/span> <span class=\"na\">port<\/span><span class=\"pi\">:<\/span> <span class=\"m\">80<\/span>\n    <span class=\"na\">targetPort<\/span><span class=\"pi\">:<\/span> <span class=\"m\">8080<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>This allowed me to build and expose two user-facing components: our Mission Control Dashboard and an interactive Customer Support chatbot.<\/p>\n\n<h3>\n  \n  \n  Main Dashboard\n<\/h3>\n\n<p><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%2Fjnk1ds7k7in6ghw7j1y1.png\" class=\"article-body-image-wrapper\"><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%2Fjnk1ds7k7in6ghw7j1y1.png\" alt=\"main dashboard\" width=\"800\" height=\"352\"><\/a><\/p>\n\n<h3>\n  \n  \n  Customer support chat\n<\/h3>\n\n<p><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%2Fge8p7j7t5q62ehycuzsm.png\" class=\"article-body-image-wrapper\"><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%2Fge8p7j7t5q62ehycuzsm.png\" alt=\"cs chat\" width=\"800\" height=\"352\"><\/a><\/p>\n\n<h2>\n  \n  \n  Why GKE Was the Perfect Choice\n<\/h2>\n\n<p>Building this complex, multi-component system in such a short time would not have been impossible without GKE. It eased the process by providing:<\/p>\n\n<ul>\n<li>\n<strong>Declarative Infrastructure:<\/strong> I could define my entire system in a few YAML files.<\/li>\n<li>\n<strong>Seamless Service Discovery:<\/strong> GKE's internal DNS let my agents find and talk to each other effortlessly.<\/li>\n<li>\n<strong>The Right Tool for the Job:<\/strong> Using <code>CronJobs<\/code> for scheduled tasks and <code>Deployments<\/code> for 24\/7 services was trivial.<\/li>\n<li>\n<strong>Built-in Resilience:<\/strong> GKE ensures that if a pod crashes, it's automatically restarted.<\/li>\n<li>\n<strong>Effortless Scalability:<\/strong> If my agents were under heavy load, scaling up would be as simple as changing <code>replicas: 1<\/code> to <code>replicas: 5<\/code>.<\/li>\n<\/ul>\n\n<p>GKE truly is the ultimate platform for building and running the next generation of AI workloads.<\/p>\n\n<h2>\n  \n  \n  The Final Architecture\n<\/h2>\n\n<p><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%2F7b61bh8u7l905ld42pkj.png\" class=\"article-body-image-wrapper\"><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%2F7b61bh8u7l905ld42pkj.png\" alt=\"Architecture Diagram\" width=\"800\" height=\"414\"><\/a><\/p>\n\n<p>\ud83d\ude80 Live Demos &amp; Code Repository<\/p>\n\n<p>Code Repository: <a href=\"https:\/\/github.com\/ki3ani\/thanos\" rel=\"noopener noreferrer\">https:\/\/github.com\/ki3ani\/thanos<\/a><\/p>\n\n<p>Live Demo: Mission Control Dashboard: <a href=\"http:\/\/34.9.104.63\/\" rel=\"noopener noreferrer\">http:\/\/34.9.104.63\/<\/a><\/p>\n\n<p>Live Demo: AI Customer Support Chatbot: <a href=\"http:\/\/34.123.10.111\/\" rel=\"noopener noreferrer\">http:\/\/34.123.10.111\/<\/a><\/p>\n\n","category":["kubernetes","ai","mcp","python"]},{"title":"Building an AI-Powered Email Assistant with Nylas and OpenAI","pubDate":"Mon, 02 Sep 2024 06:24:28 +0000","link":"https:\/\/dev.to\/ki3ani\/building-an-ai-powered-email-assistant-with-nylas-and-openai-4a5n","guid":"https:\/\/dev.to\/ki3ani\/building-an-ai-powered-email-assistant-with-nylas-and-openai-4a5n","description":"<p><em>This is a submission for the <a href=\"https:\/\/dev.to\/challenges\/nylas\">Nylas Challenge<\/a>: AI Expedition.<\/em><\/p>\n\n<h2>\n  \n  \n  What I Built and Why\n<\/h2>\n\n<p>For the <a href=\"https:\/\/dev.to\/challenges\/nylas\">Nylas Challenge: AI Expedition<\/a>, I built an AI-powered email assistant that utilizes the Nylas API and OpenAI API to enhance email management and marketing efficiency. This AI assistant is designed to:<\/p>\n\n<ul>\n<li>\n<strong>Respond to emails intelligently:<\/strong> By generating contextually relevant and human-like responses, the AI saves time and improves communication.<\/li>\n<li>\n<strong>Categorize emails using AI:<\/strong> Automatically sorts incoming emails into predefined categories based on their content, making inbox management effortless.<\/li>\n<li>\n<strong>Summarize emails using AI:<\/strong> Provides concise summaries of lengthy emails, allowing users to quickly grasp the main points without needing to read through the entire content.<\/li>\n<li>\n<strong>Handle email marketing campaigns:<\/strong> Assists in crafting and sending personalized marketing emails, leveraging AI to create compelling content and targeting the right audience.<\/li>\n<\/ul>\n\n<p>I built this project to help digital marketers, small businesses, and individuals better manage their email workflow, reduce manual effort, and improve productivity. The integration of Nylas API for email management and OpenAI API for natural language processing creates a powerful tool that meets the growing demand for intelligent, automated solutions in today's fast-paced digital environment.<\/p>\n\n<h2>\n  \n  \n  Demo\n<\/h2>\n\n<p><a href=\"https:\/\/drive.google.com\/file\/d\/13SG5fejc5ltdb11hTHBMeVr_xr7qKzV1\/view?usp=sharing\" rel=\"noopener noreferrer\">Watch the Video Demo<\/a><\/p>\n\n<h2>\n  \n  \n  Code\n<\/h2>\n\n<p><a href=\"https:\/\/github.com\/ki3ani\/coolmail\" rel=\"noopener noreferrer\">View the Code on GitHub<\/a><\/p>\n\n<h2>\n  \n  \n  Your Journey\n<\/h2>\n\n<p>For this project, I used the Nylas API for fetching and scheduling emails. The Nylas Contacts API was instrumental in obtaining recipient contacts, and I also implemented edge cases to handle contacts from emails containing CSV files or manually added contacts. I was particularly impressed by how simple and efficient it is to authenticate using Nylas, which streamlined the integration process significantly.<\/p>\n\n<p>The stack I used for building this project includes Python (Flask) for the backend, the OpenAI API for AI-powered functionalities, and the Nylas API for email and contact management. <\/p>\n\n<p>I'm most proud of successfully implementing the authentication flow and securely passing the grant ID between sessions, ensuring seamless and secure access to user data.<\/p>\n\n","category":["devchallenge","nylaschallenge","api","ai"]},{"title":"Integrating Stellar Payments into a Django Web Application","pubDate":"Mon, 19 Aug 2024 05:11:33 +0000","link":"https:\/\/dev.to\/ki3ani\/integrating-stellar-payments-into-a-django-web-application-2ecf","guid":"https:\/\/dev.to\/ki3ani\/integrating-stellar-payments-into-a-django-web-application-2ecf","description":"<p><em>This is a submission for the <a href=\"https:\/\/dev.to\/challenges\/stellar\">Build Better on Stellar: Smart Contract Challenge <\/a>: Create a Tutorial<\/em><\/p>\n\n<h2>\n  \n  \n  Introduction\n<\/h2>\n\n<p>In this tutorial, we're excited to guide you through the process of integrating Stellar payments into your Django web application. If you've ever wanted to add Stellar\u2019s powerful payment capabilities to your app, you're in the right place!<\/p>\n\n<p>We'll start with the basics, walking you through the setup required to connect your Django application to the Stellar network. You\u2019ll learn how to create Stellar accounts directly from your app, check balances to keep track of funds, send payments effortlessly, and handle other operations.<\/p>\n\n<p>Whether you're looking to implement a simple payment system or build a more complex financial feature, this guide will provide you with the tools and knowledge you need. Along the way, we'll cover key concepts, show you how to use the Stellar SDK in Python, and offer practical examples to make the integration process smooth and straightforward.<\/p>\n\n<h2>\n  \n  \n  What I Created\n<\/h2>\n\n<p>In this tutorial, I developed a Django web application with seamless Stellar payment integration. This application serves as a practical example for developers looking to incorporate Stellar\u2019s powerful payment capabilities into their own Django projects.<\/p>\n\n<h3>\n  \n  \n  Key Features of the Application:\n<\/h3>\n\n<ul>\n<li>\n<strong>User Registration and Profile Management with JWT authentication<\/strong>: Users can easily register and manage their profiles within the application. This includes updating profile details and managing account settings.<\/li>\n<li>\n<strong>Stellar Account Management<\/strong>: Users can create new Stellar accounts directly from the application, making it easy to get started with Stellar payments.<\/li>\n<li>\n<strong>Account Funding<\/strong>: The application allows users to fund their Stellar accounts, providing a straightforward way to add assets to their accounts.<\/li>\n<li>\n<strong>Sending Payments<\/strong>: Users can send payments to other Stellar accounts, facilitating smooth and efficient transactions.<\/li>\n<li>\n<strong>Transaction History<\/strong>: Users can view their transaction history, keeping track of all payment activities and account changes.<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Supporting the Stellar Developer Experience\n<\/h3>\n\n<p>This tutorial is designed to simplify the integration of Stellar payments into Django applications. By following the guide, developers will gain hands-on experience with the Stellar SDK and learn how to:<\/p>\n\n<ul>\n<li>\n<strong>Set Up Stellar Payments<\/strong>: Understand the setup process for integrating Stellar into a Django app, including configuring Stellar accounts and transactions.<\/li>\n<li>\n<strong>Use Stellar\u2019s Features<\/strong>: Explore how to leverage Stellar\u2019s capabilities for creating and managing accounts, sending payments, and more.<\/li>\n<li>\n<strong>Implement Best Practices<\/strong>: Learn best practices for integrating Stellar payments, ensuring that the application is secure, efficient, and user-friendly.<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  How This Tutorial Helps Other Developers\n<\/h3>\n\n<p>This tutorial provides a clear, step-by-step guide to integrating Stellar payments with Django, making it an invaluable resource for developers interested in blockchain and financial technology. It offers:<\/p>\n\n<ul>\n<li>\n<strong>Simplified Integration<\/strong>: A straightforward approach to adding Stellar functionality, reducing the complexity of working with blockchain technologies.<\/li>\n<li>\n<strong>Comprehensive Coverage<\/strong>: A detailed walkthrough that covers all essential aspects of Stellar integration, from account creation to transaction management.<\/li>\n<\/ul>\n\n<p>By following this tutorial, developers will not only learn how to integrate Stellar payments but also gain a deeper understanding of how to work with Stellar\u2019s API and SDK in a Django environment. This knowledge can be applied to various applications, from financial services to e-commerce platforms, expanding their capabilities and enhancing their projects.<\/p>\n\n<h2>\n  \n  \n  Journey\n<\/h2>\n\n<p>Creating this tutorial was a fascinating journey filled with learning and exploration. Here\u2019s a glimpse into the process, motivations, and experiences that shaped this project:<\/p>\n\n<h3>\n  \n  \n  Research and Content Creation\n<\/h3>\n\n<p>My journey began with a deep dive into the Stellar ecosystem and the Python Stellar SDK. I explored Stellar\u2019s documentation, tutorials, and various resources to understand how to effectively integrate Stellar payments into a Django web application. The goal was to bridge the gap between Stellar\u2019s blockchain technology and Django\u2019s robust web framework, providing a seamless and practical solution for developers.<\/p>\n\n<p>During the research phase, I focused on:<\/p>\n\n<ul>\n<li>\n<strong>Understanding Stellar\u2019s API<\/strong>: Learning how Stellar\u2019s API works, including account creation, funding, and transaction management.<\/li>\n<li>\n<strong>Exploring Django Integration<\/strong>: Figuring out the best ways to incorporate Stellar functionality into Django, ensuring smooth interactions between the web application and the Stellar network.<\/li>\n<li>\n<strong>Identifying Best Practices<\/strong>: Gathering best practices for implementing blockchain technology in web applications to ensure security, efficiency, and a great user experience.<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Motivation Behind the Submission\n<\/h3>\n\n<p>The motivation for this project stemmed from a desire to make blockchain technology more accessible to developers who are familiar with Django but may be new to Stellar. By creating a practical, easy-to-follow tutorial, I aimed to help others integrate Stellar payments into their projects without the steep learning curve.<\/p>\n\n<h3>\n  \n  \n  What I Learned\n<\/h3>\n\n<p>Throughout this process, I gained a deeper understanding of:<\/p>\n\n<ul>\n<li>\n<strong>Stellar\u2019s Capabilities<\/strong>: How Stellar\u2019s network supports various financial operations and how to leverage its features in a web application.<\/li>\n<li>\n<strong>Django Integration<\/strong>: Best practices for integrating external services into Django applications, ensuring smooth interactions and data handling.<\/li>\n<li>\n<strong>Developer Experience<\/strong>: The challenges and solutions involved in creating a user-friendly tutorial that balances technical depth with practical guidance.<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Experience with the Ecosystem\n<\/h3>\n\n<p>Working with Stellar and Django was an enriching experience. The Stellar ecosystem is vibrant and developer-friendly, offering a wealth of resources and support. Django, on the other hand, provided a robust framework for building web applications with ease. Combining these technologies highlighted the strengths of both platforms and demonstrated how they can work together effectively.<\/p>\n\n<p>Looking ahead, I hope to:<\/p>\n\n<ul>\n<li>\n<strong>Expand the Tutorial<\/strong>: Add more advanced features and examples to cover additional use cases and scenarios.<\/li>\n<li>\n<strong>Contribute to the Community<\/strong>: Share insights and improvements with the Stellar and Django communities, fostering collaboration and innovation.<\/li>\n<li>\n<strong>Explore Further Integration<\/strong>: Investigate additional ways to leverage blockchain technology in web applications, exploring new possibilities and applications.<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Prerequisites\n<\/h2>\n\n<p>Before diving into the integration of Stellar payments with Django, ensure you have the following prerequisites in place:<\/p>\n\n<ul>\n<li><p><strong>Basic Knowledge of Django<\/strong>: Familiarity with Django's core concepts, including models, views, templates, and URL routing. If you're new to Django, consider reviewing the <a href=\"https:\/\/docs.djangoproject.com\/en\/stable\/\" rel=\"noopener noreferrer\">official Django documentation<\/a> or completing a basic Django tutorial.<\/p><\/li>\n<li><p><strong>Stellar Network Understanding<\/strong>: A basic understanding of how the Stellar network operates, including key concepts like Stellar accounts, transactions, and assets. You can start with the <a href=\"https:\/\/developers.stellar.org\/\" rel=\"noopener noreferrer\">Stellar documentation<\/a>.<\/p><\/li>\n<li><p><strong>Python Programming Skills<\/strong>: Proficiency in Python, as the integration will involve writing Python code to interact with the Stellar network.<\/p><\/li>\n<li><p><strong>Stellar SDK for Python<\/strong>: Knowledge of the Stellar SDK for Python, which will be used to interact with the Stellar network. Familiarize yourself with the <a href=\"https:\/\/stellar-sdk.readthedocs.io\/en\/latest\/\" rel=\"noopener noreferrer\">Stellar SDK documentation<\/a>.<\/p><\/li>\n<li><p><strong>Development Environment<\/strong>: Ensure you have a working development environment for Django applications. This includes a code editor (like VSCode or PyCharm), Python, and Django installed on your machine.<\/p><\/li>\n<li><p><strong>API Keys and Stellar Network Setup<\/strong>: If you're planning to interact with the Stellar testnet or mainnet, you'll need to set up API keys and have a Stellar account ready. This guide will focus on using the testnet for development purposes.<\/p><\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Installation\n<\/h2>\n\n<p>To get started with integrating Stellar payments into your Django application, follow these steps to set up your development environment and install the necessary dependencies.<\/p>\n\n<h3>\n  \n  \n  1. Create a Virtual Environment\n<\/h3>\n\n<p>Using a virtual environment is a best practice in Python development to manage project-specific dependencies and avoid conflicts. To create and activate a virtual environment, run the following commands:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Create a virtual environment<\/span>\npython <span class=\"nt\">-m<\/span> venv <span class=\"nb\">env<\/span>\n\n<span class=\"c\"># Activate the virtual environment<\/span>\n<span class=\"c\"># On Windows<\/span>\n<span class=\"nb\">env<\/span><span class=\"se\">\\S<\/span>cripts<span class=\"se\">\\a<\/span>ctivate\n<span class=\"c\"># On macOS\/Linux<\/span>\n<span class=\"nb\">source env<\/span>\/bin\/activate\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  2. Install Dependencies\n<\/h2>\n\n<p>With your virtual environment activated, you'll need to install the required dependencies for the project. This includes the Stellar SDK for Python, which is essential for interacting with the Stellar network.<\/p>\n\n<h3>\n  \n  \n  Stellar SDK for Python\n<\/h3>\n\n<p>The Stellar SDK for Python provides a convenient way to interact with the Stellar blockchain from your Python application. It includes features for account creation, transaction handling, and more. To install the SDK, run:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>pip <span class=\"nb\">install <\/span>stellar-sdk\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Besides the Stellar SDK, you'll need to install Django,DRF and simplejwt for authentication:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>pip <span class=\"nb\">install <\/span>django djangorestframework djangorestframework-simplejwt\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Now that we have installed the dependencies we can now start<\/p>\n\n<h2>\n  \n  \n  Building the Application\n<\/h2>\n\n<p>In this section, we\u2019ll discuss the core components of the Django application and how they work together to provide Stellar payment functionalities. We\u2019ll explore views, utilities, models, serializers, and URLs, and show how they integrate with the Stellar network.<\/p>\n\n<h3>\n  \n  \n  1. Views\n<\/h3>\n\n<p>Views in Django handle the request\/response cycle. They process incoming requests, interact with the data models, and return responses to the client. Here's a breakdown of the views used in our application:<\/p>\n\n<h4>\n  \n  \n  StellarAccountViewSet\n<\/h4>\n\n<p>This viewset manages Stellar accounts, allowing users to perform actions such as creating an account, funding an account, checking balance, sending payments, and viewing transaction history.<\/p>\n\n<p><strong>Key Methods:<\/strong><\/p>\n\n<ul>\n<li>\n<code>create_account<\/code>: Creates a new Stellar account using the <code>create_stellar_account<\/code> utility function and saves it to the database.<\/li>\n<li>\n<code>fund_account<\/code>: Funds an existing Stellar account using the <code>fund_account<\/code> utility function.<\/li>\n<li>\n<code>check_balance<\/code>: Checks the balance of the user\u2019s Stellar account using the <code>check_account_balance<\/code> utility function.<\/li>\n<li>\n<code>send_payment<\/code>: Sends payments to other Stellar accounts using the <code>send_payment<\/code> utility function.<\/li>\n<li>\n<code>transaction_history<\/code>: Retrieves the transaction history for the user\u2019s Stellar account using the <code>get_transaction_history<\/code> utility function.<\/li>\n<\/ul>\n\n<p><strong>Code Snippet:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">class<\/span> <span class=\"nc\">StellarAccountViewSet<\/span><span class=\"p\">(<\/span><span class=\"n\">viewsets<\/span><span class=\"p\">.<\/span><span class=\"n\">ModelViewSet<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">queryset<\/span> <span class=\"o\">=<\/span> <span class=\"n\">StellarAccount<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">all<\/span><span class=\"p\">()<\/span>\n    <span class=\"n\">serializer_class<\/span> <span class=\"o\">=<\/span> <span class=\"n\">StellarAccountSerializer<\/span>\n    <span class=\"n\">permission_classes<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"n\">IsAuthenticated<\/span><span class=\"p\">]<\/span>\n\n    <span class=\"nd\">@action<\/span><span class=\"p\">(<\/span><span class=\"n\">detail<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">,<\/span> <span class=\"n\">methods<\/span><span class=\"o\">=<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">post<\/span><span class=\"sh\">'<\/span><span class=\"p\">])<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">create_account<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">request<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">public_key<\/span><span class=\"p\">,<\/span> <span class=\"n\">secret_seed<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">create_stellar_account<\/span><span class=\"p\">()<\/span>\n        <span class=\"k\">if<\/span> <span class=\"n\">public_key<\/span> <span class=\"ow\">and<\/span> <span class=\"n\">secret_seed<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">account<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">StellarAccount<\/span><span class=\"p\">(<\/span><span class=\"n\">user<\/span><span class=\"o\">=<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">user<\/span><span class=\"p\">,<\/span> <span class=\"n\">account_id<\/span><span class=\"o\">=<\/span><span class=\"n\">public_key<\/span><span class=\"p\">)<\/span>\n            <span class=\"n\">account<\/span><span class=\"p\">.<\/span><span class=\"nf\">set_secret_seed<\/span><span class=\"p\">(<\/span><span class=\"n\">secret_seed<\/span><span class=\"p\">)<\/span>\n            <span class=\"n\">account<\/span><span class=\"p\">.<\/span><span class=\"nf\">save<\/span><span class=\"p\">()<\/span>\n            <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">({<\/span><span class=\"sh\">'<\/span><span class=\"s\">public_key<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">public_key<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">secret_seed<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">secret_seed<\/span><span class=\"p\">})<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">({<\/span><span class=\"sh\">'<\/span><span class=\"s\">error<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">Failed to create the account<\/span><span class=\"sh\">'<\/span><span class=\"p\">},<\/span> <span class=\"n\">status<\/span><span class=\"o\">=<\/span><span class=\"mi\">400<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"nd\">@action<\/span><span class=\"p\">(<\/span><span class=\"n\">detail<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">,<\/span> <span class=\"n\">methods<\/span><span class=\"o\">=<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">post<\/span><span class=\"sh\">'<\/span><span class=\"p\">])<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">fund_account<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">request<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">public_key<\/span> <span class=\"o\">=<\/span> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">data<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">public_key<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">public_key<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">({<\/span><span class=\"sh\">'<\/span><span class=\"s\">error<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">Public key is required<\/span><span class=\"sh\">'<\/span><span class=\"p\">},<\/span> <span class=\"n\">status<\/span><span class=\"o\">=<\/span><span class=\"mi\">400<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">fund_account<\/span><span class=\"p\">(<\/span><span class=\"n\">public_key<\/span><span class=\"p\">)<\/span>\n            <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">({<\/span><span class=\"sh\">'<\/span><span class=\"s\">status<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">success<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">response<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">response<\/span><span class=\"p\">})<\/span>\n        <span class=\"k\">except<\/span> <span class=\"nb\">Exception<\/span> <span class=\"k\">as<\/span> <span class=\"n\">e<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">({<\/span><span class=\"sh\">'<\/span><span class=\"s\">error<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"nf\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">e<\/span><span class=\"p\">)},<\/span> <span class=\"n\">status<\/span><span class=\"o\">=<\/span><span class=\"mi\">400<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"nd\">@action<\/span><span class=\"p\">(<\/span><span class=\"n\">detail<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">,<\/span> <span class=\"n\">methods<\/span><span class=\"o\">=<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">get<\/span><span class=\"sh\">'<\/span><span class=\"p\">])<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">check_balance<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">request<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">account<\/span> <span class=\"o\">=<\/span> <span class=\"n\">StellarAccount<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">user<\/span><span class=\"o\">=<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">user<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">balances<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">check_account_balance<\/span><span class=\"p\">(<\/span><span class=\"n\">account<\/span><span class=\"p\">.<\/span><span class=\"n\">account_id<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">({<\/span><span class=\"sh\">'<\/span><span class=\"s\">balances<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">balances<\/span><span class=\"p\">})<\/span>\n\n    <span class=\"nd\">@action<\/span><span class=\"p\">(<\/span><span class=\"n\">detail<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">,<\/span> <span class=\"n\">methods<\/span><span class=\"o\">=<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">post<\/span><span class=\"sh\">'<\/span><span class=\"p\">])<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">send_payment<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">request<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">serializer<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">SendPaymentSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"o\">=<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">serializer<\/span><span class=\"p\">.<\/span><span class=\"nf\">is_valid<\/span><span class=\"p\">(<\/span><span class=\"n\">raise_exception<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">data<\/span> <span class=\"o\">=<\/span> <span class=\"n\">serializer<\/span><span class=\"p\">.<\/span><span class=\"n\">validated_data<\/span>\n\n        <span class=\"n\">from_account<\/span> <span class=\"o\">=<\/span> <span class=\"n\">StellarAccount<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">user<\/span><span class=\"o\">=<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">user<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"n\">balance<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">check_account_balance<\/span><span class=\"p\">(<\/span><span class=\"n\">from_account<\/span><span class=\"p\">.<\/span><span class=\"n\">account_id<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">if<\/span> <span class=\"nf\">any<\/span><span class=\"p\">(<\/span><span class=\"n\">b<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">asset_type<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span> <span class=\"o\">==<\/span> <span class=\"sh\">'<\/span><span class=\"s\">native<\/span><span class=\"sh\">'<\/span> <span class=\"ow\">and<\/span> <span class=\"nf\">float<\/span><span class=\"p\">(<\/span><span class=\"n\">b<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">balance<\/span><span class=\"sh\">'<\/span><span class=\"p\">])<\/span> <span class=\"o\">&lt;<\/span> <span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">amount<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span> <span class=\"k\">for<\/span> <span class=\"n\">b<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">balance<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">({<\/span><span class=\"sh\">'<\/span><span class=\"s\">error<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">Insufficient balance<\/span><span class=\"sh\">'<\/span><span class=\"p\">},<\/span> <span class=\"n\">status<\/span><span class=\"o\">=<\/span><span class=\"mi\">400<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"n\">secret_seed<\/span> <span class=\"o\">=<\/span> <span class=\"n\">from_account<\/span><span class=\"p\">.<\/span><span class=\"nf\">get_secret_seed<\/span><span class=\"p\">()<\/span>  <span class=\"c1\"># Decrypt the secret seed\n<\/span>        <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">send_payment<\/span><span class=\"p\">(<\/span><span class=\"n\">from_account<\/span><span class=\"p\">,<\/span> <span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">to_account<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span> <span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">amount<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span> <span class=\"n\">secret_seed<\/span><span class=\"o\">=<\/span><span class=\"n\">secret_seed<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">({<\/span><span class=\"sh\">'<\/span><span class=\"s\">response<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">response<\/span><span class=\"p\">})<\/span>\n\n    <span class=\"nd\">@action<\/span><span class=\"p\">(<\/span><span class=\"n\">detail<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">,<\/span> <span class=\"n\">methods<\/span><span class=\"o\">=<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">get<\/span><span class=\"sh\">'<\/span><span class=\"p\">])<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">transaction_history<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">request<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">account<\/span> <span class=\"o\">=<\/span> <span class=\"n\">StellarAccount<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">user<\/span><span class=\"o\">=<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">user<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">transactions<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">get_transaction_history<\/span><span class=\"p\">(<\/span><span class=\"n\">account<\/span><span class=\"p\">.<\/span><span class=\"n\">account_id<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">({<\/span><span class=\"sh\">'<\/span><span class=\"s\">transactions<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">transactions<\/span><span class=\"p\">})<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  2. Utilities\n<\/h3>\n\n<p>Utility functions perform the actual operations with the Stellar network, such as account creation, funding, and payment transactions.<\/p>\n\n<p><strong>Key Functions:<\/strong><\/p>\n\n<ul>\n<li>\n<strong><code>create_stellar_account<\/code><\/strong>: Creates a new Stellar account and returns the public key and secret seed.<\/li>\n<li>\n<strong><code>check_account_balance<\/code><\/strong>: Checks the balance of a Stellar account.<\/li>\n<li>\n<strong><code>send_payment<\/code><\/strong>: Sends a payment to another Stellar account.<\/li>\n<li>\n<strong><code>get_transaction_history<\/code><\/strong>: Retrieves the transaction history for a Stellar account.<\/li>\n<li>\n<strong><code>fund_account<\/code><\/strong>: Funds a Stellar account.<\/li>\n<\/ul>\n\n<p><strong>Code Snippet:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">def<\/span> <span class=\"nf\">get_fernet<\/span><span class=\"p\">():<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nc\">Fernet<\/span><span class=\"p\">(<\/span><span class=\"n\">settings<\/span><span class=\"p\">.<\/span><span class=\"n\">SECRET_KEY<\/span><span class=\"p\">.<\/span><span class=\"nf\">encode<\/span><span class=\"p\">())<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">encrypt_data<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">fernet<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">get_fernet<\/span><span class=\"p\">()<\/span>\n    <span class=\"n\">encrypted<\/span> <span class=\"o\">=<\/span> <span class=\"n\">fernet<\/span><span class=\"p\">.<\/span><span class=\"nf\">encrypt<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">.<\/span><span class=\"nf\">encode<\/span><span class=\"p\">())<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">encrypted<\/span><span class=\"p\">.<\/span><span class=\"nf\">decode<\/span><span class=\"p\">()<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">decrypt_data<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">fernet<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">get_fernet<\/span><span class=\"p\">()<\/span>\n    <span class=\"n\">decrypted<\/span> <span class=\"o\">=<\/span> <span class=\"n\">fernet<\/span><span class=\"p\">.<\/span><span class=\"nf\">decrypt<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">.<\/span><span class=\"nf\">encode<\/span><span class=\"p\">())<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">decrypted<\/span><span class=\"p\">.<\/span><span class=\"nf\">decode<\/span><span class=\"p\">()<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">create_stellar_account<\/span><span class=\"p\">():<\/span>\n    <span class=\"n\">keypair<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Keypair<\/span><span class=\"p\">.<\/span><span class=\"nf\">random<\/span><span class=\"p\">()<\/span>\n    <span class=\"n\">public_key<\/span> <span class=\"o\">=<\/span> <span class=\"n\">keypair<\/span><span class=\"p\">.<\/span><span class=\"n\">public_key<\/span>\n    <span class=\"n\">secret_seed<\/span> <span class=\"o\">=<\/span> <span class=\"n\">keypair<\/span><span class=\"p\">.<\/span><span class=\"n\">secret<\/span>\n\n    <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n        <span class=\"nf\">fund_account<\/span><span class=\"p\">(<\/span><span class=\"n\">public_key<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">public_key<\/span><span class=\"p\">,<\/span> <span class=\"n\">secret_seed<\/span>\n    <span class=\"k\">except<\/span> <span class=\"nb\">Exception<\/span> <span class=\"k\">as<\/span> <span class=\"n\">e<\/span><span class=\"p\">:<\/span>\n        <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Error funding account: <\/span><span class=\"si\">{<\/span><span class=\"n\">e<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"bp\">None<\/span><span class=\"p\">,<\/span> <span class=\"bp\">None<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">fund_account<\/span><span class=\"p\">(<\/span><span class=\"n\">public_key<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">friendbot_url<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">https:\/\/friendbot.stellar.org<\/span><span class=\"sh\">\"<\/span>\n    <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">requests<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">friendbot_url<\/span><span class=\"p\">,<\/span> <span class=\"n\">params<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">addr<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">public_key<\/span><span class=\"p\">})<\/span> \n\n    <span class=\"k\">if<\/span> <span class=\"n\">response<\/span><span class=\"p\">.<\/span><span class=\"n\">status_code<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">200<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">response<\/span><span class=\"p\">.<\/span><span class=\"nf\">json<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">else<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">raise<\/span> <span class=\"nc\">Exception<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Failed to fund account: <\/span><span class=\"si\">{<\/span><span class=\"n\">response<\/span><span class=\"p\">.<\/span><span class=\"n\">text<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">check_account_balance<\/span><span class=\"p\">(<\/span><span class=\"n\">account_id<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">server<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Server<\/span><span class=\"p\">(<\/span><span class=\"n\">horizon_url<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">https:\/\/horizon-testnet.stellar.org<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">account<\/span> <span class=\"o\">=<\/span> <span class=\"n\">server<\/span><span class=\"p\">.<\/span><span class=\"nf\">accounts<\/span><span class=\"p\">().<\/span><span class=\"nf\">account_id<\/span><span class=\"p\">(<\/span><span class=\"n\">account_id<\/span><span class=\"p\">).<\/span><span class=\"nf\">call<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">account<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">balances<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">send_payment<\/span><span class=\"p\">(<\/span><span class=\"n\">from_account<\/span><span class=\"p\">,<\/span> <span class=\"n\">to_account<\/span><span class=\"p\">,<\/span> <span class=\"n\">amount<\/span><span class=\"p\">,<\/span> <span class=\"n\">asset_code<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">XLM<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">asset_issuer<\/span><span class=\"o\">=<\/span><span class=\"bp\">None<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">server<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Server<\/span><span class=\"p\">(<\/span><span class=\"n\">horizon_url<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">https:\/\/horizon-testnet.stellar.org<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">source_keypair<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Keypair<\/span><span class=\"p\">.<\/span><span class=\"nf\">from_secret<\/span><span class=\"p\">(<\/span><span class=\"n\">from_account<\/span><span class=\"p\">.<\/span><span class=\"nf\">get_secret_seed<\/span><span class=\"p\">())<\/span>  <span class=\"c1\"># Decrypt secret seed\n<\/span>    <span class=\"n\">source_account<\/span> <span class=\"o\">=<\/span> <span class=\"n\">server<\/span><span class=\"p\">.<\/span><span class=\"nf\">load_account<\/span><span class=\"p\">(<\/span><span class=\"n\">account_id<\/span><span class=\"o\">=<\/span><span class=\"n\">from_account<\/span><span class=\"p\">.<\/span><span class=\"n\">account_id<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">base_fee<\/span> <span class=\"o\">=<\/span> <span class=\"n\">server<\/span><span class=\"p\">.<\/span><span class=\"nf\">fetch_base_fee<\/span><span class=\"p\">()<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"n\">asset_code<\/span> <span class=\"o\">==<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">XLM<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">asset<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Asset<\/span><span class=\"p\">.<\/span><span class=\"nf\">native<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">else<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">asset<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Asset<\/span><span class=\"p\">(<\/span><span class=\"n\">asset_code<\/span><span class=\"p\">,<\/span> <span class=\"n\">asset_issuer<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">transaction<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">TransactionBuilder<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">source_account<\/span><span class=\"o\">=<\/span><span class=\"n\">source_account<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">network_passphrase<\/span><span class=\"o\">=<\/span><span class=\"n\">Network<\/span><span class=\"p\">.<\/span><span class=\"n\">TESTNET_NETWORK_PASSPHRASE<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">base_fee<\/span><span class=\"o\">=<\/span><span class=\"n\">base_fee<\/span>\n    <span class=\"p\">).<\/span><span class=\"nf\">add_text_memo<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Test Transaction<\/span><span class=\"sh\">\"<\/span><span class=\"p\">).<\/span><span class=\"nf\">append_payment_op<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">destination<\/span><span class=\"o\">=<\/span><span class=\"n\">to_account<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">amount<\/span><span class=\"o\">=<\/span><span class=\"nf\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">amount<\/span><span class=\"p\">),<\/span>\n        <span class=\"n\">asset<\/span><span class=\"o\">=<\/span><span class=\"n\">asset<\/span>\n    <span class=\"p\">).<\/span><span class=\"nf\">build<\/span><span class=\"p\">()<\/span>\n\n    <span class=\"n\">transaction<\/span><span class=\"p\">.<\/span><span class=\"nf\">sign<\/span><span class=\"p\">(<\/span><span class=\"n\">source_keypair<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">server<\/span><span class=\"p\">.<\/span><span class=\"nf\">submit_transaction<\/span><span class=\"p\">(<\/span><span class=\"n\">transaction<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">response<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">get_transaction_history<\/span><span class=\"p\">(<\/span><span class=\"n\">account_id<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">server<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Server<\/span><span class=\"p\">(<\/span><span class=\"n\">horizon_url<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">https:\/\/horizon-testnet.stellar.org<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">transactions<\/span> <span class=\"o\">=<\/span> <span class=\"n\">server<\/span><span class=\"p\">.<\/span><span class=\"nf\">transactions<\/span><span class=\"p\">().<\/span><span class=\"nf\">for_account<\/span><span class=\"p\">(<\/span><span class=\"n\">account_id<\/span><span class=\"p\">).<\/span><span class=\"nf\">call<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">transactions<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">_embedded<\/span><span class=\"sh\">'<\/span><span class=\"p\">][<\/span><span class=\"sh\">'<\/span><span class=\"s\">records<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  3. Models\n<\/h3>\n\n<p>In this section, we'll define the models used to handle Stellar account information and user profiles in your Django application.<\/p>\n\n<h4>\n  \n  \n  <code>StellarAccount<\/code> Model\n<\/h4>\n\n<p>The <code>StellarAccount<\/code> model is responsible for storing information about Stellar accounts linked to users. <\/p>\n\n<ul>\n<li>\n<strong>Purpose<\/strong>: Links Stellar accounts to Django users and manages sensitive data securely.<\/li>\n<li>\n<strong>Fields<\/strong>:\n\n<ul>\n<li>\n<code>user<\/code>: A <code>OneToOneField<\/code> linking each Stellar account to a Django <code>User<\/code>.<\/li>\n<li>\n<code>account_id<\/code>: A <code>CharField<\/code> storing the public key for the Stellar account.<\/li>\n<li>\n<code>secret_seed<\/code>: A <code>CharField<\/code> for storing the encrypted secret seed used for transactions.<\/li>\n<li>\n<code>created_at<\/code>: A <code>DateTimeField<\/code> that automatically records the account creation timestamp.<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\n<strong>Methods<\/strong>:\n\n<ul>\n<li>\n<code>set_secret_seed(secret_seed)<\/code>: Encrypts and sets the secret seed.<\/li>\n<li>\n<code>get_secret_seed()<\/code>: Decrypts and retrieves the secret seed.<\/li>\n<\/ul>\n\n\n<\/li>\n\n<\/ul>\n\n<p><strong>Example<\/strong>:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">class<\/span> <span class=\"nc\">StellarAccount<\/span><span class=\"p\">(<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">Model<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">user<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">OneToOneField<\/span><span class=\"p\">(<\/span><span class=\"n\">User<\/span><span class=\"p\">,<\/span> <span class=\"n\">on_delete<\/span><span class=\"o\">=<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">CASCADE<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">account_id<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">CharField<\/span><span class=\"p\">(<\/span><span class=\"n\">max_length<\/span><span class=\"o\">=<\/span><span class=\"mi\">56<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">secret_seed<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">CharField<\/span><span class=\"p\">(<\/span><span class=\"n\">max_length<\/span><span class=\"o\">=<\/span><span class=\"mi\">256<\/span><span class=\"p\">)<\/span>  <span class=\"c1\"># Increased length for encrypted data\n<\/span>    <span class=\"n\">created_at<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">DateTimeField<\/span><span class=\"p\">(<\/span><span class=\"n\">auto_now_add<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">__str__<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">):<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">account_id<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">set_secret_seed<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">secret_seed<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">secret_seed<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">encrypt_data<\/span><span class=\"p\">(<\/span><span class=\"n\">secret_seed<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">get_secret_seed<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">):<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nf\">decrypt_data<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">secret_seed<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>We can also include the model for user profiles:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code>\n<span class=\"k\">class<\/span> <span class=\"nc\">UserProfile<\/span><span class=\"p\">(<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">Model<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">user<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">OneToOneField<\/span><span class=\"p\">(<\/span><span class=\"n\">User<\/span><span class=\"p\">,<\/span> <span class=\"n\">on_delete<\/span><span class=\"o\">=<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">CASCADE<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">first_name<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">CharField<\/span><span class=\"p\">(<\/span><span class=\"n\">max_length<\/span><span class=\"o\">=<\/span><span class=\"mi\">30<\/span><span class=\"p\">,<\/span> <span class=\"n\">blank<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">last_name<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">CharField<\/span><span class=\"p\">(<\/span><span class=\"n\">max_length<\/span><span class=\"o\">=<\/span><span class=\"mi\">30<\/span><span class=\"p\">,<\/span> <span class=\"n\">blank<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">email<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">EmailField<\/span><span class=\"p\">(<\/span><span class=\"n\">blank<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">profile_picture<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">ImageField<\/span><span class=\"p\">(<\/span><span class=\"n\">upload_to<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">profile_pictures\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">blank<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span> <span class=\"n\">null<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">__str__<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">):<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">user<\/span><span class=\"p\">.<\/span><span class=\"n\">username<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  4. Serializers Overview\n<\/h3>\n\n<p>In this section, we define the serializers used to handle data validation and transformation for the Stellar account, user profile, and payment operations.<\/p>\n\n<h3>\n  \n  \n  <code>StellarAccountSerializer<\/code>\n<\/h3>\n\n<p>The <code>StellarAccountSerializer<\/code> manages serialization and deserialization of <code>StellarAccount<\/code> model instances.<\/p>\n\n<ul>\n<li>\n<strong>Purpose<\/strong>: Converts <code>StellarAccount<\/code> model instances to JSON and vice versa.<\/li>\n<li>\n<strong>Fields<\/strong>:\n\n<ul>\n<li><code>user<\/code><\/li>\n<li><code>account_id<\/code><\/li>\n<li><code>secret_seed<\/code><\/li>\n<li>\n<code>created_at<\/code>\n<\/li>\n<\/ul>\n\n\n<\/li>\n\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">rest_framework<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">serializers<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">.models<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">StellarAccount<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">StellarAccountSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">serializers<\/span><span class=\"p\">.<\/span><span class=\"n\">ModelSerializer<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">class<\/span> <span class=\"nc\">Meta<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">model<\/span> <span class=\"o\">=<\/span> <span class=\"n\">StellarAccount<\/span>\n        <span class=\"n\">fields<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">user<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">account_id<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">secret_seed<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">created_at<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>and <\/p>\n\n<h2>\n  \n  \n  <code>SendPaymentSerializer<\/code>\n<\/h2>\n\n<p>The <code>SendPaymentSerializer<\/code> handles the serialization of payment data and includes validation for the payment amount.<\/p>\n\n<ul>\n<li>\n<strong>Purpose<\/strong>: Validates and serializes payment requests.<\/li>\n<li>\n<strong>Fields<\/strong>:\n\n<ul>\n<li>\n<code>to_account<\/code>: The Stellar account ID of the recipient.<\/li>\n<li>\n<code>amount<\/code>: The amount to be sent.\n<\/li>\n<\/ul>\n\n\n<\/li>\n\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">rest_framework<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">serializers<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">pydantic<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">ValidationError<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">SendPaymentSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">serializers<\/span><span class=\"p\">.<\/span><span class=\"n\">Serializer<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">to_account<\/span> <span class=\"o\">=<\/span> <span class=\"n\">serializers<\/span><span class=\"p\">.<\/span><span class=\"nc\">CharField<\/span><span class=\"p\">(<\/span><span class=\"n\">max_length<\/span><span class=\"o\">=<\/span><span class=\"mi\">56<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">amount<\/span> <span class=\"o\">=<\/span> <span class=\"n\">serializers<\/span><span class=\"p\">.<\/span><span class=\"nc\">DecimalField<\/span><span class=\"p\">(<\/span><span class=\"n\">max_digits<\/span><span class=\"o\">=<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"n\">decimal_places<\/span><span class=\"o\">=<\/span><span class=\"mi\">2<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">validate_amount<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span><span class=\"p\">):<\/span>\n        <span class=\"k\">if<\/span> <span class=\"n\">value<\/span> <span class=\"o\">&lt;=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">raise<\/span> <span class=\"nc\">ValidationError<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Amount must be greater than zero.<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">value<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>We should also add serializers for user management<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">class<\/span> <span class=\"nc\">UserProfileSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">serializers<\/span><span class=\"p\">.<\/span><span class=\"n\">ModelSerializer<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">class<\/span> <span class=\"nc\">Meta<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">model<\/span> <span class=\"o\">=<\/span> <span class=\"n\">UserProfile<\/span>\n        <span class=\"n\">fields<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">user<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">first_name<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">last_name<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">email<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">profile_picture<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n\n\n<span class=\"k\">class<\/span> <span class=\"nc\">UserRegistrationSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">serializers<\/span><span class=\"p\">.<\/span><span class=\"n\">ModelSerializer<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">class<\/span> <span class=\"nc\">Meta<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">model<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">get_user_model<\/span><span class=\"p\">()<\/span>\n        <span class=\"n\">fields<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">username<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">password<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n        <span class=\"n\">extra_kwargs<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"sh\">'<\/span><span class=\"s\">password<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span><span class=\"sh\">'<\/span><span class=\"s\">write_only<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"bp\">True<\/span><span class=\"p\">}}<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">create<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">validated_data<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">user<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">get_user_model<\/span><span class=\"p\">().<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">create_user<\/span><span class=\"p\">(<\/span><span class=\"o\">**<\/span><span class=\"n\">validated_data<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">UserProfile<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">create<\/span><span class=\"p\">(<\/span><span class=\"n\">user<\/span><span class=\"o\">=<\/span><span class=\"n\">user<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">user<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>and finally we can add URLs map incoming requests to the appropriate views in the urls.py:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">django.urls<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">path<\/span><span class=\"p\">,<\/span> <span class=\"n\">include<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">rest_framework.routers<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">DefaultRouter<\/span>\n\n<span class=\"kn\">from<\/span> <span class=\"n\">.views<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">StellarAccountViewSet<\/span><span class=\"p\">,<\/span> <span class=\"n\">UserProfileViewSet<\/span>\n\n\n<span class=\"n\">router<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">DefaultRouter<\/span><span class=\"p\">()<\/span>\n<span class=\"n\">router<\/span><span class=\"p\">.<\/span><span class=\"nf\">register<\/span><span class=\"p\">(<\/span><span class=\"sa\">r<\/span><span class=\"sh\">'<\/span><span class=\"s\">stellar_accounts<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">StellarAccountViewSet<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">router<\/span><span class=\"p\">.<\/span><span class=\"nf\">register<\/span><span class=\"p\">(<\/span><span class=\"sa\">r<\/span><span class=\"sh\">'<\/span><span class=\"s\">user_profiles<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">UserProfileViewSet<\/span><span class=\"p\">)<\/span>\n\n\n<span class=\"n\">urlpatterns<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n    <span class=\"nf\">path<\/span><span class=\"p\">(<\/span><span class=\"sh\">''<\/span><span class=\"p\">,<\/span> <span class=\"nf\">include<\/span><span class=\"p\">(<\/span><span class=\"n\">router<\/span><span class=\"p\">.<\/span><span class=\"n\">urls<\/span><span class=\"p\">)),<\/span>\n<span class=\"p\">]<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>We can now be able to test our app using Postman to see our app at work<\/p>\n\n<h3>\n  \n  \n  Postman Testing\n<\/h3>\n\n<h4>\n  \n  \n  Create Account\n<\/h4>\n\n<p><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%2Fd5pa8oaq72st2k6mmtnp.png\" class=\"article-body-image-wrapper\"><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%2Fd5pa8oaq72st2k6mmtnp.png\" alt=\"Image description\" width=\"800\" height=\"346\"><\/a><\/p>\n\n<h4>\n  \n  \n  Sending Payments\n<\/h4>\n\n<p><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%2F0gjxyt5wszz7qur4acu7.png\" class=\"article-body-image-wrapper\"><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%2F0gjxyt5wszz7qur4acu7.png\" alt=\"Image description\" width=\"800\" height=\"415\"><\/a><\/p>\n\n<h4>\n  \n  \n  Check Balance\n<\/h4>\n\n<p><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%2F9r9ewa53rdwmctaoz26i.png\" class=\"article-body-image-wrapper\"><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%2F9r9ewa53rdwmctaoz26i.png\" alt=\"Image description\" width=\"800\" height=\"415\"><\/a><\/p>\n\n<h4>\n  \n  \n  Token\n<\/h4>\n\n<p><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%2Fc4t542su2hlccxnjtwvc.png\" class=\"article-body-image-wrapper\"><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%2Fc4t542su2hlccxnjtwvc.png\" alt=\"Image description\" width=\"800\" height=\"346\"><\/a><\/p>\n\n<blockquote>\n<p>We are using jwt for authentication<\/p>\n<\/blockquote>\n\n<h4>\n  \n  \n  Register\n<\/h4>\n\n<p><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%2F0vbmdx6l1dox8mirtavb.png\" class=\"article-body-image-wrapper\"><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%2F0vbmdx6l1dox8mirtavb.png\" alt=\"Image description\" width=\"800\" height=\"346\"><\/a><\/p>\n\n<h4>\n  \n  \n  Transaction History\n<\/h4>\n\n<p><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%2Fyvy1rvirqcwfifc6j109.png\" class=\"article-body-image-wrapper\"><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%2Fyvy1rvirqcwfifc6j109.png\" alt=\"Image description\" width=\"800\" height=\"415\"><\/a><\/p>\n\n<h4>\n  \n  \n  User Profile\n<\/h4>\n\n<p><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%2Fw9773nnmmv50ii5ji49f.png\" class=\"article-body-image-wrapper\"><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%2Fw9773nnmmv50ii5ji49f.png\" alt=\"Image description\" width=\"800\" height=\"415\"><\/a><\/p>\n\n<blockquote>\n<p>A user profile is create on create for every user<\/p>\n<\/blockquote>\n\n<p>In this tutorial, we explored how to integrate Stellar payments into a Django web application. We covered the setup of Stellar accounts, encrypted sensitive data, managed user profiles, and implemented the functionality for sending payments. By following these steps, you can now leverage the power of Stellar's blockchain technology to facilitate secure and efficient transactions within your Django projects. You can also have a look at the GitHub repo here:  <a href=\"https:\/\/github.com\/ki3ani\/Stellar-Payments\" rel=\"noopener noreferrer\">GitHub link<\/a>.<\/p>\n\n","category":["devchallenge","stellarchallenge","blockchain","web3"]},{"title":"Building a TaskManager Serverless Python Api with AWS Lambda, API Gateway, CloudWatch events, DynamoDB and Cognito","pubDate":"Sun, 04 Aug 2024 17:06:46 +0000","link":"https:\/\/dev.to\/ki3ani\/building-a-taskmanager-serverless-python-app-with-aws-lambda-api-gateway-cloudwatch-events-and-cognito-5f3k","guid":"https:\/\/dev.to\/ki3ani\/building-a-taskmanager-serverless-python-app-with-aws-lambda-api-gateway-cloudwatch-events-and-cognito-5f3k","description":"<h1>\n  \n  \n  Introduction\n<\/h1>\n\n<p>Welcome, tech enthusiasts and coding adventurers! \ud83d\ude80<\/p>\n\n<p>Have you ever dreamed of building a sleek, serverless Task Manager that effortlessly scales in the cloud? Whether you're setting out to create a handy to-do list or are simply fascinated by serverless technology, you\u2019re in the right spot. In this tutorial, we\u2019ll harness the power of AWS Lambda, API Gateway, DynamoDB, and Cognito to craft a robust Task Manager API.<\/p>\n\n<p>We\u2019ll explore how to manage tasks, implement authentication with Cognito, and set up automated reminders, all while keeping our infrastructure maintenance-free. Ready to dive into serverless computing and build something awesome? Let\u2019s get started and transform your task management ideas into a fully functional reality!<\/p>\n\n<h2>\n  \n  \n  Prerequisites\n<\/h2>\n\n<p>Before we dive into building our serverless Task Manager API, here are a few things you'll need:<\/p>\n\n<ul>\n<li>\n<strong>AWS Account<\/strong>: Ensure you have an AWS account set up. If you don\u2019t, you can create one <a href=\"https:\/\/aws.amazon.com\/\" rel=\"noopener noreferrer\">here<\/a>.<\/li>\n<li>\n<strong>Basic Knowledge of AWS Services<\/strong>: Familiarity with AWS Lambda, API Gateway, DynamoDB, and Cognito will be helpful. If you're new to these services, check out the <a href=\"https:\/\/docs.aws.amazon.com\/\" rel=\"noopener noreferrer\">AWS documentation<\/a> for a quick overview.<\/li>\n<li>\n<strong>Programming Skills<\/strong>: Some experience with Python will be useful, as we'll be using it for our Lambda functions. If you're new to Python, you might want to brush up on the basics.<\/li>\n<li>\n<strong>Postman<\/strong>: We\u2019ll use Postman for testing our API endpoints. You can download it <a href=\"https:\/\/www.postman.com\/downloads\/\" rel=\"noopener noreferrer\">here<\/a>.<\/li>\n<li>\n<strong>Basic Knowledge of JSON<\/strong>: Since our API will interact using JSON, a basic understanding of JSON formatting will be beneficial.<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Objectives\n<\/h2>\n\n<p>By the end of this tutorial, you'll have built a serverless Task Manager API with the following features:<\/p>\n\n<ul>\n<li>\n<strong>Create Tasks<\/strong>: Users will be able to create tasks with titles, descriptions, due dates, and categories. Each task will be associated with a unique ID and stored in DynamoDB.<\/li>\n<li>\n<strong>Retrieve Tasks<\/strong>: Users will be able to retrieve all their tasks or fetch a specific task by its ID.<\/li>\n<li>\n<strong>Update Tasks<\/strong>: Users will have the ability to update the details of their tasks, including title, description, due date, and category.<\/li>\n<li>\n<strong>Delete Tasks<\/strong>: Users will be able to delete tasks they no longer need.<\/li>\n<li>\n<strong>Automated Reminders<\/strong>: Our system will automatically send SMS reminders for tasks that are due, thanks to AWS Lambda's scheduled events and integration with Twilio.<\/li>\n<li>\n<strong>Secure Access<\/strong>: We'll use AWS Cognito to handle user authentication, ensuring that only authorized users can interact with their tasks.<\/li>\n<li>\n<strong>Efficient Querying<\/strong>: We'll utilize a Global Secondary Index (GSI) in DynamoDB to efficiently query tasks based on the <code>due_date<\/code>. This allows us to easily retrieve tasks that are due on a specific date.<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  DynamoDB Setup\n<\/h2>\n\n<h3>\n  \n  \n  Creating the DynamoDB Table\n<\/h3>\n\n<p>To store and manage our tasks efficiently, we'll set up a DynamoDB table. Follow these steps:<\/p>\n\n<ol>\n<li>\n<p><strong>Create a DynamoDB Table<\/strong>:<\/p>\n\n<ul>\n<li>\n<strong>Table Name<\/strong>: <code>Tasks<\/code>\n<\/li>\n<li>\n<strong>Primary Key<\/strong>: \n\n<ul>\n<li>\n<strong>Partition Key<\/strong>: <code>task_id<\/code> (String)<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Attributes<\/strong>:<\/p>\n\n<ul>\n<li>\n<strong>task_id<\/strong>: A unique identifier for each task.<\/li>\n<li>\n<strong>user_id<\/strong>: The ID of the user who created the task.<\/li>\n<li>\n<strong>title<\/strong>: The title of the task.<\/li>\n<li>\n<strong>description<\/strong>: A brief description of the task.<\/li>\n<li>\n<strong>due_date<\/strong>: The due date of the task.<\/li>\n<li>\n<strong>status<\/strong>: The current status of the task (e.g., pending, completed).<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n<h3>\n  \n  \n  Setting Up a Global Secondary Index (GSI)\n<\/h3>\n\n<p>To optimize our task retrieval based on due dates, we've set up ## Setting Up API Gateway for Task Manager<\/p>\n\n<h3>\n  \n  \n  Overview\n<\/h3>\n\n<p>In this section, we'll walk through the setup of API Gateway for our Task Manager application. This API Gateway is designed to handle CRUD operations for tasks, including creating, retrieving, updating, and deleting tasks, and it integrates with AWS Lambda functions for processing these operations.<\/p>\n\n<h3>\n  \n  \n  Step-by-Step Setup\n<\/h3>\n\n<ol>\n<li><strong>Create API Gateway<\/strong><\/li>\n<\/ol>\n\n<ul>\n<li>\n<strong>Navigate to API Gateway<\/strong>: Open the AWS Management Console and navigate to API Gateway.<\/li>\n<li>\n<strong>Create a New API<\/strong>: Choose \"Create API\" and select \"REST API\" for our use case.<\/li>\n<\/ul>\n\n<ol>\n<li><strong>Define Resources and Methods<\/strong><\/li>\n<\/ol>\n\n<ul>\n<li>\n<p><strong>Create <code>\/tasks<\/code> Resource<\/strong>:<\/p>\n\n<ul>\n<li>\n<strong>GET Method<\/strong>: Connect this method to a Lambda function that retrieves all tasks from the DynamoDB table.<\/li>\n<li>\n<strong>POST Method<\/strong>: Connect this method to a Lambda function that creates a new task in DynamoDB.<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\n<p><strong>Create <code>\/tasks\/{taskId}<\/code> Resource<\/strong>:<\/p>\n\n<ul>\n<li>\n<strong>GET Method<\/strong>: Connect this method to a Lambda function that retrieves a specific task by ID from DynamoDB.<\/li>\n<li>\n<strong>PUT Method<\/strong>: Connect this method to a Lambda function that updates a specific task by ID in DynamoDB.<\/li>\n<li>\n<strong>DELETE Method<\/strong>: Connect this method to a Lambda function that deletes a specific task by ID from DynamoDB.<\/li>\n<\/ul>\n\n\n<\/li>\n\n<\/ul>\n\n<ol>\n<li><strong>Set Up Authorization<\/strong><\/li>\n<\/ol>\n\n<ul>\n<li>\n<strong>Authorization Type<\/strong>: Use Cognito Authorizer to secure the API endpoints.<\/li>\n<li>\n<strong>Configure Cognito Authorizer<\/strong>: \n\n<ul>\n<li>In the API Gateway console, go to \"Authorizers\" and create a new Cognito Authorizer.<\/li>\n<li>Link this authorizer to your API methods to enforce authentication.<\/li>\n<\/ul>\n\n\n<\/li>\n\n<\/ul>\n\n<ol>\n<li><strong>API Key Settings<\/strong><\/li>\n<\/ol>\n\n<ul>\n<li>\n<strong>API Key Required<\/strong>: Set this to \"No\" as API keys are not required for this API.<\/li>\n<\/ul>\n\n<ol>\n<li><strong>Request Validation<\/strong><\/li>\n<\/ol>\n\n<ul>\n<li>\n<strong>Request Validator<\/strong>: No request validator is applied, meaning no schema validation is enforced for incoming requests.<\/li>\n<\/ul>\n\n<ol>\n<li><strong>SDK Operation Naming<\/strong><\/li>\n<\/ol>\n\n<ul>\n<li>\n<strong>SDK Operation Name<\/strong>: The SDK operation names are generated automatically based on the method and path. This naming helps in integrating the API with client SDKs.<\/li>\n<\/ul>\n\n<ol>\n<li><strong>Deploy the API<\/strong><\/li>\n<\/ol>\n\n<ul>\n<li>\n<strong>Create a Deployment Stage<\/strong>: After configuring the methods and settings, create a deployment stage (e.g., <code>prod<\/code>) and deploy your API.<\/li>\n<\/ul>\n\n<ol>\n<li><strong>Test the API<\/strong><\/li>\n<\/ol>\n\n<ul>\n<li>\n<strong>Test Endpoints<\/strong>: Use tools like Postman or cURL to test the endpoints and ensure they work as expected.<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Summary\n<\/h3>\n\n<p>With these steps, you've successfully set up API Gateway to handle CRUD operations for your Task Manager application, connecting each API method to its corresponding Lambda function. The integration with AWS Cognito provides secure access, while the configuration ensures that the API is ready for deployment and testing.<br>\na Global Secondary Index (GSI) on our DynamoDB table. Here are the details:<\/p>\n\n<ul>\n<li>\n<strong>Index Name<\/strong>: <code>UserDueDateIndex<\/code>\n<\/li>\n<li>\n<strong>Partition Key<\/strong>: <code>user_id<\/code> (String)<\/li>\n<li>\n<strong>Sort Key<\/strong>: <code>due_date<\/code> (String)<\/li>\n<li>\n<strong>Read Capacity<\/strong>: 5 (Auto scaling is off)<\/li>\n<li>\n<strong>Write Capacity<\/strong>: 5 (Auto scaling is off)<\/li>\n<li>\n<strong>Projected Attributes<\/strong>: All<\/li>\n<\/ul>\n\n<p>This index helps us efficiently fetch tasks that are due on a specific date for a particular user, ensuring our reminders and queries are both fast and scalable.<\/p>\n<h3>\n  \n  \n  Steps to Create the GSI\n<\/h3>\n\n<ol>\n<li>\n<p><strong>Navigate to DynamoDB in the AWS Console<\/strong>:<\/p>\n\n<ul>\n<li>Go to the DynamoDB service in your AWS Management Console.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Select Your Table<\/strong>:<\/p>\n\n<ul>\n<li>Choose the <code>Tasks<\/code> table you created earlier.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Create Global Secondary Index<\/strong>:<\/p>\n\n<ul>\n<li>Go to the \"Indexes\" tab and select \"Create Index\".<\/li>\n<li>Set the Index Name to <code>UserDueDateIndex<\/code>.<\/li>\n<li>Set the Partition Key to <code>user_id<\/code> (String).<\/li>\n<li>Set the Sort Key to <code>due_date<\/code> (String).<\/li>\n<li>Configure Read and Write Capacity as needed (for our example, we set both to 5 and turned off auto-scaling).<\/li>\n<li>Select \"All\" for Projected Attributes to include all attributes in the index.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h2>\n  \n  \n  AWS Cognito Integration\n<\/h2>\n<h3>\n  \n  \n  Overview\n<\/h3>\n\n<p>AWS Cognito provides user authentication and authorization services, allowing you to easily add user sign-up, sign-in, and access control features to your application. For our serverless Task Manager API, we've integrated AWS Cognito to handle user authentication, ensuring that only authorized users can interact with their tasks.<\/p>\n<h3>\n  \n  \n  Setting Up AWS Cognito\n<\/h3>\n\n<ol>\n<li><p><strong>Create a User Pool<\/strong>: First, you'll need to create a User Pool in AWS Cognito. This pool will manage your users, handle sign-ups, and provide user authentication.<\/p><\/li>\n<li><p><strong>Configure App Client<\/strong>: Within your User Pool, create an App Client. This client will be used by your application to interact with Cognito. Make sure to configure the callback and sign-out URLs as needed for your application.<\/p><\/li>\n<\/ol>\n\n<p><strong>Callback URLs<\/strong>: These are the URLs where users will be redirected after they successfully sign in or sign out. Make sure to include the URL of your front-end application here. For example, if your front-end is hosted on S3, the callback URL might be <code>https:\/\/your-frontend-bucket.s3.amazonaws.com\/auth\/callback<\/code>.<\/p>\n\n<p><strong>Sign-Out URLs<\/strong>: These are the URLs where users will be redirected after they sign out. Typically, this would be your application's home page.<\/p>\n\n<ol>\n<li>\n<strong>Set Up Cognito Authorizer in API Gateway<\/strong>:\n\n<ul>\n<li>\n<strong>Create a Cognito Authorizer<\/strong>: In API Gateway, create a new Cognito Authorizer and associate it with the User Pool you created. This authorizer will be used to validate the JWT tokens sent by clients.<\/li>\n<li>\n<strong>Attach the Authorizer to Your API<\/strong>: Apply the Cognito Authorizer to the routes in your API Gateway. This ensures that requests to your Lambda functions are authenticated.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n<blockquote>\n<p><strong>P.S.:<\/strong> Remember to save your <code>client_id<\/code>, <code>user_pool_id<\/code>, and <code>domain<\/code>. These values are crucial for configuring your application to interact with Cognito. You can find them in the AWS Cognito console:<\/p>\n\n<ul>\n<li>\n<strong>Client ID<\/strong>: Found in the \"App Clients\" section of your User Pool.<\/li>\n<li>\n<strong>User Pool ID<\/strong>: Found in the \"General settings\" section of your User Pool.<\/li>\n<li>\n<strong>Domain<\/strong>: Found in the \"Domain name\" section under \"App integration\".<\/li>\n<\/ul>\n<\/blockquote>\n<h3>\n  \n  \n  How Cognito Works in Our Task Manager API\n<\/h3>\n\n<ol>\n<li><p><strong>User Authentication<\/strong>: When a user signs up or signs in, they receive a JWT token from Cognito. This token is used to authenticate their requests.<\/p><\/li>\n<li><p><strong>Authorization Header<\/strong>: Users must include the JWT token in the <code>Authorization<\/code> header of their requests. Our Lambda functions will decode and verify this token to ensure the request is made by an authorized user.<\/p><\/li>\n<li><p><strong>Token Validation<\/strong>: Each Lambda function extracts the token from the <code>Authorization<\/code> header, decodes it using the Cognito public keys, and validates it. If the token is valid, the request is processed; otherwise, an error is returned.<\/p><\/li>\n<\/ol>\n<h3>\n  \n  \n  Implementing Cognito in Lambda Functions\n<\/h3>\n\n<p>Here's how the integration is implemented in the Lambda functions:<\/p>\n\n<ul>\n<li><p><strong>Extract and Decode Token<\/strong>: Each Lambda function extracts the JWT token from the <code>Authorization<\/code> header and decodes it to extract the user ID.<\/p><\/li>\n<li><p><strong>Verify Token<\/strong>: The token is verified to ensure it was issued by AWS Cognito and is still valid. We use the <code>jwt<\/code> library to handle decoding and verification.<\/p><\/li>\n<li><p><strong>Authorize Requests<\/strong>: Based on the decoded user ID, the Lambda function processes the request if the token is valid. If the token is missing or invalid, an appropriate error message is returned.<\/p><\/li>\n<\/ul>\n<h3>\n  \n  \n  Example Code\n<\/h3>\n\n<p>Here\u2019s a snippet of how the JWT token is handled in one of our Lambda functions:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">import<\/span> <span class=\"n\">jwt<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">lambda_handler<\/span><span class=\"p\">(<\/span><span class=\"n\">event<\/span><span class=\"p\">,<\/span> <span class=\"n\">context<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n        <span class=\"c1\"># Extract JWT token from the Authorization header\n<\/span>        <span class=\"n\">auth_header<\/span> <span class=\"o\">=<\/span> <span class=\"n\">event<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">headers<\/span><span class=\"sh\">'<\/span><span class=\"p\">][<\/span><span class=\"sh\">'<\/span><span class=\"s\">Authorization<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n        <span class=\"n\">token<\/span> <span class=\"o\">=<\/span> <span class=\"n\">auth_header<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">()[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span>\n\n        <span class=\"c1\"># Decode and verify the token\n<\/span>        <span class=\"n\">decoded_token<\/span> <span class=\"o\">=<\/span> <span class=\"n\">jwt<\/span><span class=\"p\">.<\/span><span class=\"nf\">decode<\/span><span class=\"p\">(<\/span><span class=\"n\">token<\/span><span class=\"p\">,<\/span> <span class=\"n\">options<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">verify_signature<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"bp\">False<\/span><span class=\"p\">})<\/span>\n        <span class=\"n\">user_id<\/span> <span class=\"o\">=<\/span> <span class=\"n\">decoded_token<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">sub<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n\n        <span class=\"c1\"># Process the request if token is valid\n<\/span>\n    <span class=\"k\">except<\/span> <span class=\"nb\">Exception<\/span> <span class=\"k\">as<\/span> <span class=\"n\">e<\/span><span class=\"p\">:<\/span>\n        <span class=\"c1\"># Handle errors\n<\/span>        <span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">statusCode<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">401<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">body<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">json<\/span><span class=\"p\">.<\/span><span class=\"nf\">dumps<\/span><span class=\"p\">({<\/span><span class=\"sh\">'<\/span><span class=\"s\">error<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"nf\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">e<\/span><span class=\"p\">)})<\/span>\n        <span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  AWS Lambda Functions\n<\/h2>\n\n<p>In our serverless Task Manager application, we use several AWS Lambda functions to handle the core functionality. Here\u2019s a breakdown of each function and its role in the application:<\/p>\n\n<h3>\n  \n  \n  1. Create Task Function\n<\/h3>\n\n<p>This function handles creating a new task in the DynamoDB table.<\/p>\n\n<p><strong>Key Parts<\/strong>:<\/p>\n\n<ul>\n<li>\n<strong>Input Parsing and Validation<\/strong>: Parses the request body and ensures all required fields are present.<\/li>\n<li>\n<strong>Task Creation<\/strong>: Generates a unique task ID and prepares the task item for storage.<\/li>\n<li>\n<strong>DynamoDB Post Operation<\/strong>: Inserts the new task into the DynamoDB table.\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># Parse the request body\n<\/span><span class=\"n\">body<\/span> <span class=\"o\">=<\/span> <span class=\"n\">json<\/span><span class=\"p\">.<\/span><span class=\"nf\">loads<\/span><span class=\"p\">(<\/span><span class=\"n\">event<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">body<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">{}<\/span><span class=\"sh\">'<\/span><span class=\"p\">))<\/span>\n<span class=\"n\">task_title<\/span> <span class=\"o\">=<\/span> <span class=\"n\">body<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">title<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">task_title<\/span><span class=\"p\">:<\/span>\n    <span class=\"k\">raise<\/span> <span class=\"nc\">ValueError<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Task title is required<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"n\">task_description<\/span> <span class=\"o\">=<\/span> <span class=\"n\">body<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">description<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">''<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">due_date<\/span> <span class=\"o\">=<\/span> <span class=\"n\">body<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">due_date<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\"># Generate a unique task ID\n<\/span><span class=\"n\">task_id<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">uuid<\/span><span class=\"p\">.<\/span><span class=\"nf\">uuid4<\/span><span class=\"p\">())<\/span>\n<span class=\"n\">item<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">user_id<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">user_id<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">task_id<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">task_id<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">title<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">task_title<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">description<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">task_description<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">created_at<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">datetime<\/span><span class=\"p\">.<\/span><span class=\"nf\">now<\/span><span class=\"p\">().<\/span><span class=\"nf\">isoformat<\/span><span class=\"p\">(),<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">status<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">pending<\/span><span class=\"sh\">'<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">if<\/span> <span class=\"n\">due_date<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">item<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">due_date<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">due_date<\/span>\n\n<span class=\"n\">category<\/span> <span class=\"o\">=<\/span> <span class=\"n\">body<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">category<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">if<\/span> <span class=\"n\">category<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">item<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">category<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">category<\/span>\n\n<span class=\"c1\"># Store the item in DynamoDB\n<\/span><span class=\"n\">table<\/span><span class=\"p\">.<\/span><span class=\"nf\">put_item<\/span><span class=\"p\">(<\/span><span class=\"n\">Item<\/span><span class=\"o\">=<\/span><span class=\"n\">item<\/span><span class=\"p\">)<\/span>\n\n<span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Task created successfully: <\/span><span class=\"si\">{<\/span><span class=\"n\">task_id<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">statusCode<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">201<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">body<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">json<\/span><span class=\"p\">.<\/span><span class=\"nf\">dumps<\/span><span class=\"p\">({<\/span><span class=\"sh\">'<\/span><span class=\"s\">message<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">Task created successfully<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">task_id<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">task_id<\/span><span class=\"p\">})<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  2. Get Tasks Function\n<\/h3>\n\n<p>This function retrieves all tasks associated with the currently authenticated user from the DynamoDB table.<\/p>\n\n<p><strong>Key Parts<\/strong>:<\/p>\n\n<ul>\n<li>\n<strong>Query DynamoDB<\/strong>: Fetches tasks from DynamoDB based on the user ID.\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># Fetch tasks from DynamoDB\n<\/span><span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">table<\/span><span class=\"p\">.<\/span><span class=\"nf\">query<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">KeyConditionExpression<\/span><span class=\"o\">=<\/span><span class=\"nc\">Key<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">user_id<\/span><span class=\"sh\">'<\/span><span class=\"p\">).<\/span><span class=\"nf\">eq<\/span><span class=\"p\">(<\/span><span class=\"n\">user_id<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">)<\/span>\n\n<span class=\"n\">tasks<\/span> <span class=\"o\">=<\/span> <span class=\"n\">response<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">Items<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">[])<\/span>\n\n<span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Retrieved <\/span><span class=\"si\">{<\/span><span class=\"nf\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">tasks<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"s\"> tasks for user: <\/span><span class=\"si\">{<\/span><span class=\"n\">user_id<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">statusCode<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">200<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">body<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">json<\/span><span class=\"p\">.<\/span><span class=\"nf\">dumps<\/span><span class=\"p\">(<\/span><span class=\"n\">tasks<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  3. Get Task by ID Function\n<\/h3>\n\n<p>This function retrieves a specific task by its ID from the DynamoDB table.<\/p>\n\n<p><strong>Key Parts<\/strong>:<\/p>\n\n<ul>\n<li>\n<strong>Retrieve Task from DynamoDB<\/strong>: Queries DynamoDB to fetch a specific task based on the user ID and task ID.\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># Get task_id from path parameters\n<\/span><span class=\"n\">task_id<\/span> <span class=\"o\">=<\/span> <span class=\"n\">event<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">pathParameters<\/span><span class=\"sh\">'<\/span><span class=\"p\">][<\/span><span class=\"sh\">'<\/span><span class=\"s\">taskId<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n\n<span class=\"c1\"># Query the item from DynamoDB\n<\/span><span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">table<\/span><span class=\"p\">.<\/span><span class=\"nf\">get_item<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">Key<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">user_id<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">user_id<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">task_id<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">task_id<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">)<\/span>\n\n<span class=\"n\">task<\/span> <span class=\"o\">=<\/span> <span class=\"n\">response<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">Item<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">task<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">warning<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Task not found: <\/span><span class=\"si\">{<\/span><span class=\"n\">task_id<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">statusCode<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">404<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">body<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">json<\/span><span class=\"p\">.<\/span><span class=\"nf\">dumps<\/span><span class=\"p\">({<\/span><span class=\"sh\">'<\/span><span class=\"s\">message<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">Task not found<\/span><span class=\"sh\">'<\/span><span class=\"p\">})<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Task retrieved successfully: <\/span><span class=\"si\">{<\/span><span class=\"n\">task_id<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">statusCode<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">200<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">body<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">json<\/span><span class=\"p\">.<\/span><span class=\"nf\">dumps<\/span><span class=\"p\">(<\/span><span class=\"n\">task<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  4. Update Task Function\n<\/h3>\n\n<p>This function updates an existing task in the DynamoDB table.<\/p>\n\n<p><strong>Key Parts<\/strong>:<\/p>\n\n<ul>\n<li>\n<strong>Prepare Update Expression<\/strong>: Constructs the update expression dynamically based on the provided fields.\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># Parse the request body\n<\/span><span class=\"k\">if<\/span> <span class=\"sh\">'<\/span><span class=\"s\">body<\/span><span class=\"sh\">'<\/span> <span class=\"ow\">not<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">event<\/span><span class=\"p\">:<\/span>\n    <span class=\"k\">raise<\/span> <span class=\"nc\">ValueError<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Request body is missing<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"n\">body<\/span> <span class=\"o\">=<\/span> <span class=\"n\">json<\/span><span class=\"p\">.<\/span><span class=\"nf\">loads<\/span><span class=\"p\">(<\/span><span class=\"n\">event<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">body<\/span><span class=\"sh\">'<\/span><span class=\"p\">])<\/span>\n<span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Request body: <\/span><span class=\"si\">{<\/span><span class=\"n\">body<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\"># Get task_id from path parameters\n<\/span><span class=\"k\">if<\/span> <span class=\"sh\">'<\/span><span class=\"s\">pathParameters<\/span><span class=\"sh\">'<\/span> <span class=\"ow\">not<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">event<\/span> <span class=\"ow\">or<\/span> <span class=\"sh\">'<\/span><span class=\"s\">taskId<\/span><span class=\"sh\">'<\/span> <span class=\"ow\">not<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">event<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">pathParameters<\/span><span class=\"sh\">'<\/span><span class=\"p\">]:<\/span>\n    <span class=\"k\">raise<\/span> <span class=\"nc\">ValueError<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">taskId is missing in path parameters<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">task_id<\/span> <span class=\"o\">=<\/span> <span class=\"n\">event<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">pathParameters<\/span><span class=\"sh\">'<\/span><span class=\"p\">][<\/span><span class=\"sh\">'<\/span><span class=\"s\">taskId<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n\n<span class=\"c1\"># Treat the entire body as updates\n<\/span><span class=\"n\">updates<\/span> <span class=\"o\">=<\/span> <span class=\"n\">body<\/span>\n\n<span class=\"c1\"># Prepare the update expression\n<\/span><span class=\"n\">update_expression<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">SET <\/span><span class=\"sh\">\"<\/span>\n<span class=\"n\">expression_attribute_values<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{}<\/span>\n<span class=\"n\">expression_attribute_names<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{}<\/span>\n\n<span class=\"k\">for<\/span> <span class=\"n\">key<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">updates<\/span><span class=\"p\">.<\/span><span class=\"nf\">items<\/span><span class=\"p\">():<\/span>\n    <span class=\"n\">update_expression<\/span> <span class=\"o\">+=<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">#<\/span><span class=\"si\">{<\/span><span class=\"n\">key<\/span><span class=\"si\">}<\/span><span class=\"s\"> = :<\/span><span class=\"si\">{<\/span><span class=\"n\">key<\/span><span class=\"si\">}<\/span><span class=\"s\">, <\/span><span class=\"sh\">\"<\/span>\n    <span class=\"n\">expression_attribute_values<\/span><span class=\"p\">[<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">:<\/span><span class=\"si\">{<\/span><span class=\"n\">key<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">value<\/span>\n    <span class=\"n\">expression_attribute_names<\/span><span class=\"p\">[<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">#<\/span><span class=\"si\">{<\/span><span class=\"n\">key<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">key<\/span>\n\n<span class=\"n\">update_expression<\/span> <span class=\"o\">=<\/span> <span class=\"n\">update_expression<\/span><span class=\"p\">.<\/span><span class=\"nf\">rstrip<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">, <\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Update expression: <\/span><span class=\"si\">{<\/span><span class=\"n\">update_expression<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Expression attribute values: <\/span><span class=\"si\">{<\/span><span class=\"n\">expression_attribute_values<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Expression attribute names: <\/span><span class=\"si\">{<\/span><span class=\"n\">expression_attribute_names<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\"># Update the item in DynamoDB\n<\/span><span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">table<\/span><span class=\"p\">.<\/span><span class=\"nf\">update_item<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">Key<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">user_id<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">user_id<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">task_id<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">task_id<\/span>\n    <span class=\"p\">},<\/span>\n    <span class=\"n\">UpdateExpression<\/span><span class=\"o\">=<\/span><span class=\"n\">update_expression<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">ExpressionAttributeValues<\/span><span class=\"o\">=<\/span><span class=\"n\">expression_attribute_values<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">ExpressionAttributeNames<\/span><span class=\"o\">=<\/span><span class=\"n\">expression_attribute_names<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">ReturnValues<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">ALL_NEW<\/span><span class=\"sh\">\"<\/span>\n<span class=\"p\">)<\/span>\n\n<span class=\"n\">updated_task<\/span> <span class=\"o\">=<\/span> <span class=\"n\">response<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">Attributes<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n\n<span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Task updated successfully: <\/span><span class=\"si\">{<\/span><span class=\"n\">task_id<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Updated task: <\/span><span class=\"si\">{<\/span><span class=\"n\">updated_task<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">statusCode<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">200<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">body<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">json<\/span><span class=\"p\">.<\/span><span class=\"nf\">dumps<\/span><span class=\"p\">(<\/span><span class=\"n\">updated_task<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  5. Delete Task Function\n<\/h3>\n\n<p>This function deletes a specific task from the DynamoDB table.<\/p>\n\n<p><strong>Key Parts<\/strong>:<\/p>\n\n<ul>\n<li>\n<strong>Delete Item from DynamoDB<\/strong>: Uses the <code>delete_item<\/code> method to remove the task based on <code>user_id<\/code> and <code>task_id<\/code>.\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># Get task_id from path parameters\n<\/span><span class=\"k\">if<\/span> <span class=\"sh\">'<\/span><span class=\"s\">pathParameters<\/span><span class=\"sh\">'<\/span> <span class=\"ow\">not<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">event<\/span> <span class=\"ow\">or<\/span> <span class=\"sh\">'<\/span><span class=\"s\">taskId<\/span><span class=\"sh\">'<\/span> <span class=\"ow\">not<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">event<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">pathParameters<\/span><span class=\"sh\">'<\/span><span class=\"p\">]:<\/span>\n    <span class=\"k\">raise<\/span> <span class=\"nc\">ValueError<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">task_id is missing in path parameters<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">task_id<\/span> <span class=\"o\">=<\/span> <span class=\"n\">event<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">pathParameters<\/span><span class=\"sh\">'<\/span><span class=\"p\">][<\/span><span class=\"sh\">'<\/span><span class=\"s\">taskId<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n\n<span class=\"c1\"># Delete the item from DynamoDB\n<\/span><span class=\"n\">table<\/span><span class=\"p\">.<\/span><span class=\"nf\">delete_item<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">Key<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">user_id<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">user_id<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">task_id<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">task_id<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">)<\/span>\n\n<span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Task deleted successfully: <\/span><span class=\"si\">{<\/span><span class=\"n\">task_id<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">statusCode<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">200<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">body<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">json<\/span><span class=\"p\">.<\/span><span class=\"nf\">dumps<\/span><span class=\"p\">({<\/span><span class=\"sh\">'<\/span><span class=\"s\">message<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">Task deleted successfully<\/span><span class=\"sh\">'<\/span><span class=\"p\">})<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  6. Sending Reminders Function\n<\/h3>\n\n<p>This function sends SMS reminders for tasks due on the current date.<\/p>\n\n<p><strong>Key Parts<\/strong>:<\/p>\n\n<ul>\n<li>\n<strong>Query DynamoDB for Due Tasks<\/strong>: Queries the <code>UserDueDateIndex<\/code> for tasks due today.<\/li>\n<li>\n<strong>Send SMS Reminders<\/strong>: Uses Twilio's API to send SMS reminders to users.\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">def<\/span> <span class=\"nf\">send_reminder_sms<\/span><span class=\"p\">(<\/span><span class=\"n\">phone_number<\/span><span class=\"p\">,<\/span> <span class=\"n\">task_title<\/span><span class=\"p\">,<\/span> <span class=\"n\">due_date<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">ACCOUNT_SID<\/span> <span class=\"o\">=<\/span> <span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"n\">environ<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">TWILIO_ACCOUNT_SID<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n    <span class=\"n\">AUTH_TOKEN<\/span> <span class=\"o\">=<\/span> <span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"n\">environ<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">TWILIO_AUTH_TOKEN<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n    <span class=\"n\">TWILIO_PHONE_NUMBER<\/span> <span class=\"o\">=<\/span> <span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"n\">environ<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">TWILIO_PHONE_NUMBER<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n\n    <span class=\"n\">client<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Client<\/span><span class=\"p\">(<\/span><span class=\"n\">ACCOUNT_SID<\/span><span class=\"p\">,<\/span> <span class=\"n\">AUTH_TOKEN<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">MESSAGE<\/span> <span class=\"o\">=<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Reminder: Your task <\/span><span class=\"sh\">'<\/span><span class=\"si\">{<\/span><span class=\"n\">task_title<\/span><span class=\"si\">}<\/span><span class=\"sh\">'<\/span><span class=\"s\"> is due on <\/span><span class=\"si\">{<\/span><span class=\"n\">due_date<\/span><span class=\"si\">}<\/span><span class=\"s\">.<\/span><span class=\"sh\">\"<\/span>\n\n    <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">message<\/span> <span class=\"o\">=<\/span> <span class=\"n\">client<\/span><span class=\"p\">.<\/span><span class=\"n\">messages<\/span><span class=\"p\">.<\/span><span class=\"nf\">create<\/span><span class=\"p\">(<\/span>\n            <span class=\"n\">body<\/span><span class=\"o\">=<\/span><span class=\"n\">MESSAGE<\/span><span class=\"p\">,<\/span>\n            <span class=\"n\">from_<\/span><span class=\"o\">=<\/span><span class=\"n\">TWILIO_PHONE_NUMBER<\/span><span class=\"p\">,<\/span>\n            <span class=\"n\">to<\/span><span class=\"o\">=<\/span><span class=\"n\">phone_number<\/span>\n        <span class=\"p\">)<\/span>\n        <span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">SMS sent! Message SID: <\/span><span class=\"si\">{<\/span><span class=\"n\">message<\/span><span class=\"p\">.<\/span><span class=\"n\">sid<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">except<\/span> <span class=\"nb\">Exception<\/span> <span class=\"k\">as<\/span> <span class=\"n\">e<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">error<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Error sending SMS: <\/span><span class=\"si\">{<\/span><span class=\"n\">e<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">lambda_handler<\/span><span class=\"p\">(<\/span><span class=\"n\">event<\/span><span class=\"p\">,<\/span> <span class=\"n\">context<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">today_date<\/span> <span class=\"o\">=<\/span> <span class=\"n\">datetime<\/span><span class=\"p\">.<\/span><span class=\"nf\">utcnow<\/span><span class=\"p\">().<\/span><span class=\"nf\">strftime<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">%Y-%m-%d<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">table<\/span><span class=\"p\">.<\/span><span class=\"nf\">query<\/span><span class=\"p\">(<\/span>\n            <span class=\"n\">IndexName<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">UserDueDateIndex<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"n\">KeyConditionExpression<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">due_date = :due_date<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"n\">ExpressionAttributeValues<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"sh\">'<\/span><span class=\"s\">:due_date<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">today_date<\/span><span class=\"p\">}<\/span>\n        <span class=\"p\">)<\/span>\n\n        <span class=\"n\">tasks<\/span> <span class=\"o\">=<\/span> <span class=\"n\">response<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">Items<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">[])<\/span>\n        <span class=\"k\">for<\/span> <span class=\"n\">task<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">tasks<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">phone_number<\/span> <span class=\"o\">=<\/span> <span class=\"n\">task<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">phone_number<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n            <span class=\"n\">task_title<\/span> <span class=\"o\">=<\/span> <span class=\"n\">task<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">title<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">No Title<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n            <span class=\"n\">due_date<\/span> <span class=\"o\">=<\/span> <span class=\"n\">task<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">due_date<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">No Due Date<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n            <span class=\"nf\">send_reminder_sms<\/span><span class=\"p\">(<\/span><span class=\"n\">phone_number<\/span><span class=\"p\">,<\/span> <span class=\"n\">task_title<\/span><span class=\"p\">,<\/span> <span class=\"n\">due_date<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">statusCode<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">200<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">body<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">SMS reminders sent successfully<\/span><span class=\"sh\">'<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"k\">except<\/span> <span class=\"nb\">Exception<\/span> <span class=\"k\">as<\/span> <span class=\"n\">e<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">error<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Error processing tasks: <\/span><span class=\"si\">{<\/span><span class=\"n\">e<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">statusCode<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">500<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">body<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">'<\/span><span class=\"s\">Error processing tasks: <\/span><span class=\"si\">{<\/span><span class=\"n\">e<\/span><span class=\"si\">}<\/span><span class=\"sh\">'<\/span>\n        <span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Here is one of the lambda functions on the console(note: we will integrate the gateway in the coming steps):<\/p>\n\n<p><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%2Fg6np3uxpv2z9rdy5vuip.png\" class=\"article-body-image-wrapper\"><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%2Fg6np3uxpv2z9rdy5vuip.png\" alt=\"Image description\" width=\"800\" height=\"386\"><\/a><\/p>\n\n<h2>\n  \n  \n  Packaging and Deploying Lambda Functions\n<\/h2>\n\n<p>After implementing the Lambda functions for your serverless Task Manager API, you need to package them with their dependencies and deploy them to AWS Lambda. Follow these steps:<\/p>\n\n<h3>\n  \n  \n  1. Packaging Lambda Functions\n<\/h3>\n\n<p><strong>1.1 Prepare Your Environment<\/strong><\/p>\n\n<p>Ensure you have Python and <code>pip<\/code> installed on your local machine.<\/p>\n\n<p><strong>1.2 Create a Project Directory<\/strong><\/p>\n\n<p>Create a directory for each Lambda function. For example:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nb\">mkdir <\/span>lambda_get_tasks\n<span class=\"nb\">mkdir <\/span>lambda_get_task_by_id\n<span class=\"nb\">mkdir <\/span>lambda_update_task\n<span class=\"nb\">mkdir <\/span>lambda_delete_task\n<span class=\"nb\">mkdir <\/span>lambda_send_reminders\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>1.3 Install Dependencies<\/strong><\/p>\n\n<p>Navigate to each directory and install the required Python packages.<\/p>\n\n<ul>\n<li>For <code>GetTasks<\/code>, <code>GetTaskById<\/code>, <code>UpdateTask<\/code>, and <code>DeleteTask<\/code> functions:\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>  <span class=\"nb\">cd <\/span>lambda_get_tasks\n  pip <span class=\"nb\">install <\/span>pyjwt boto3 <span class=\"nt\">-t<\/span> <span class=\"nb\">.<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>For <code>SendReminders<\/code> Function (which includes <code>twilio<\/code>):<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nb\">cd<\/span> ..\/lambda_send_reminders\npip <span class=\"nb\">install <\/span>pyjwt boto3 twilio <span class=\"nt\">-t<\/span> <span class=\"nb\">.<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>1.4 Add Your Lambda Function Code<\/strong><\/p>\n\n<p>Place your Lambda function code in a file named <code>lambda_function.py<\/code> within the respective directory.<\/p>\n\n<p><strong>1.5 Zip Your Lambda Function<\/strong><\/p>\n\n<p>Navigate to the directory containing your Lambda function code and dependencies. Create a ZIP file of the contents:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nb\">cd <\/span>lambda_get_tasks\nzip <span class=\"nt\">-r<\/span> lambda_function.zip <span class=\"nb\">.<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Repeat the zipping process for each function directory.<\/p>\n\n<p><strong>1.6 Upload to AWS Lambda Console<\/strong><\/p>\n\n<ol>\n<li>Log in to the <a href=\"https:\/\/console.aws.amazon.com\/lambda\" rel=\"noopener noreferrer\">AWS Lambda Console<\/a>.<\/li>\n<li>Create a new Lambda function or select an existing one.<\/li>\n<li>In the function configuration, choose <strong>Upload from .zip file<\/strong> and upload the corresponding <code>lambda_function.zip<\/code> file.<\/li>\n<\/ol>\n\n<p><strong>2. Configuring Environment Variables<\/strong><\/p>\n\n<p>For the Lambda functions that require environment variables, follow these steps:<\/p>\n\n<h4>\n  \n  \n  2.1 Navigate to Your Lambda Function\n<\/h4>\n\n<ol>\n<li>In the AWS Lambda Console, select your Lambda function.<\/li>\n<\/ol>\n\n<h4>\n  \n  \n  2.2 Configure Environment Variables\n<\/h4>\n\n<ol>\n<li>Go to the <strong>Configuration<\/strong> tab.<\/li>\n<li>Select <strong>Environment variables<\/strong>.<\/li>\n<li>Click on <strong>Edit<\/strong> and add the required environment variables:<\/li>\n<\/ol>\n\n<ul>\n<li>\n<p>For the <code>SendReminders<\/code> function, add:<\/p>\n\n<ul>\n<li><code>TWILIO_ACCOUNT_SID<\/code><\/li>\n<li><code>TWILIO_AUTH_TOKEN<\/code><\/li>\n<li><code>TWILIO_PHONE_NUMBER<\/code><\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\n<p>Add any additional environment variables required for your functions, such as:<\/p>\n\n<ul>\n<li>\n<code>DYNAMODB_TABLE_NAME<\/code> (for functions that interact with DynamoDB in our case its the Tasks table)<\/li>\n<\/ul>\n\n\n<\/li>\n\n<\/ul>\n\n<h4>\n  \n  \n  2.3 Save Changes\n<\/h4>\n\n<h3>\n  \n  \n  Setting Up API Gateway for Task Manager\n<\/h3>\n\n<h3>\n  \n  \n  Overview\n<\/h3>\n\n<p>In this section, we'll walk through the setup of API Gateway for our Task Manager application. This API Gateway is designed to handle CRUD operations for tasks, including creating, retrieving, updating, and deleting tasks, and it integrates with AWS Lambda functions for processing these operations.<\/p>\n\n<h3>\n  \n  \n  Step-by-Step Setup\n<\/h3>\n\n<ul>\n<li>\n<p><strong>Create API Gateway<\/strong><\/p>\n\n<ul>\n<li>\n<strong>Navigate to API Gateway<\/strong>: Open the AWS Management Console and navigate to API Gateway.<\/li>\n<li>\n<strong>Create a New API<\/strong>: Choose \"Create API\" and select \"REST API\" for our use case.<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\n<p><strong>Define Resources and Methods<\/strong><\/p>\n\n<ul>\n<li><strong>Create <code>\/tasks<\/code> Resource<\/strong><\/li>\n<li>\n<strong>GET Method<\/strong>: Connect this method to a Lambda function that retrieves all tasks from the DynamoDB table.<\/li>\n<li>\n<strong>POST Method<\/strong>: Connect this method to a Lambda function that creates a new task in DynamoDB.<\/li>\n<li><strong>Create <code>\/tasks\/{taskId}<\/code> Resource<\/strong><\/li>\n<li>\n<strong>GET Method<\/strong>: Connect this method to a Lambda function that retrieves a specific task by ID from DynamoDB.<\/li>\n<li>\n<strong>PUT Method<\/strong>: Connect this method to a Lambda function that updates a specific task by ID in DynamoDB.<\/li>\n<li>\n<strong>DELETE Method<\/strong>: Connect this method to a Lambda function that deletes a specific task by ID from DynamoDB.<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\n<p><strong>Set Up Authorization<\/strong><\/p>\n\n<ul>\n<li>\n<strong>Authorization Type<\/strong>: Use Cognito Authorizer to secure the API endpoints.<\/li>\n<li><strong>Configure Cognito Authorizer<\/strong><\/li>\n<li>In the API Gateway console, go to \"Authorizers\" and create a new Cognito Authorizer.<\/li>\n<li>Link this authorizer to your API methods to enforce authentication.<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\n<p><strong>API Key Settings<\/strong><\/p>\n\n<ul>\n<li>\n<strong>API Key Required<\/strong>: Set this to \"No\" as API keys are not required for this API.<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\n<p><strong>Request Validation<\/strong><\/p>\n\n<ul>\n<li>\n<strong>Request Validator<\/strong>: No request validator is applied, meaning no schema validation is enforced for incoming requests.<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\n<p><strong>SDK Operation Naming<\/strong><\/p>\n\n<ul>\n<li>\n<strong>SDK Operation Name<\/strong>: The SDK operation names are generated automatically based on the method and path. This naming helps in integrating the API with client SDKs.<\/li>\n<\/ul>\n\n\n<\/li>\n\n<\/ul>\n\n<p>Here is how the API looks like and a sample of a function endpoint:<\/p>\n\n<p><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%2Flpqgwrzcrbig2xlzhxc1.png\" class=\"article-body-image-wrapper\"><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%2Flpqgwrzcrbig2xlzhxc1.png\" alt=\"Image description\" width=\"800\" height=\"402\"><\/a><\/p>\n\n<p><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%2Ff8hheiehetczojefdzq1.png\" class=\"article-body-image-wrapper\"><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%2Ff8hheiehetczojefdzq1.png\" alt=\"Image description\" width=\"800\" height=\"402\"><\/a><\/p>\n\n<ul>\n<li>\n<p><strong>Deploy the API<\/strong><\/p>\n\n<ul>\n<li>\n<strong>Create a Deployment Stage<\/strong>: After configuring the methods and settings, create a deployment stage (e.g., <code>prod<\/code>) and deploy your API.<\/li>\n<\/ul>\n\n\n<\/li>\n\n<\/ul>\n\n<h3>\n  \n  \n  Summary\n<\/h3>\n\n<p>With these steps, you've successfully set up API Gateway to handle CRUD operations for your Task Manager application, connecting each API method to its corresponding Lambda function. The integration with AWS Cognito provides secure access, while the configuration ensures that the API is ready for deployment and testing.<\/p>\n\n<h3>\n  \n  \n  CloudWatch Events for Scheduling Reminders\n<\/h3>\n\n<p>To ensure that the reminder functionality operates daily and sends SMS reminders for tasks due on the current date, we use AWS CloudWatch Events. This service allows us to create scheduled events that trigger Lambda functions at specified intervals.<\/p>\n\n<ol>\n<li><strong>Create a CloudWatch Rule<\/strong><\/li>\n<\/ol>\n\n<ul>\n<li>\n<strong>Navigate to CloudWatch<\/strong>: Open the AWS Management Console and go to CloudWatch.<\/li>\n<li>\n<strong>Create a Rule<\/strong>: Select \"Rules\" under \"Events\" and click \"Create rule.\"<\/li>\n<li>\n<p><strong>Define the Schedule<\/strong>: Choose \"Event Source\" and select \"Schedule.\" Use the cron expression <code>cron(0 6 * * ? *)<\/code> to run the Lambda function daily at 9 AM in the Africa\/Nairobi time zone.<\/p>\n\n<p><strong>Cron Expression Breakdown<\/strong>:<\/p>\n\n<ul>\n<li>\n<code>0 6 * * ? *<\/code>: This expression schedules the event to run at 6:00 AM UTC daily. Adjust for your desired time zone if needed.<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li><p><strong>Target<\/strong>: Set the target as the Lambda function responsible for sending reminders. Choose the Lambda function you configured for this purpose.<\/p><\/li>\n\n<\/ul>\n\n<ol>\n<li><strong>Configure Permissions<\/strong><\/li>\n<\/ol>\n\n<ul>\n<li>\n<strong>IAM Role<\/strong>: Ensure that the Lambda function's execution role has the necessary permissions to interact with DynamoDB, send SMS via Twilio, and log events to CloudWatch Logs.<\/li>\n<li>\n<strong>Event Permissions<\/strong>: Confirm that CloudWatch Events can invoke the Lambda function. This is typically set up automatically when configuring the rule.<\/li>\n<\/ul>\n\n<ol>\n<li><strong>Save and Test<\/strong><\/li>\n<\/ol>\n\n<ul>\n<li>\n<strong>Save the Rule<\/strong>: After configuring the schedule and targets, save the rule.<\/li>\n<li>\n<strong>Test the Setup<\/strong>: You can manually trigger the Lambda function to test its functionality or wait for the scheduled time to confirm it operates as expected.<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Testing the API with Postman\n<\/h2>\n\n<h3>\n  \n  \n  Overview\n<\/h3>\n\n<p>In this section, we'll test the Task Manager API using Postman. Before testing, you'll need to obtain an authorization code and exchange it for an access token.<\/p>\n\n<h3>\n  \n  \n  Step 1: Obtain Authorization Code\n<\/h3>\n\n<ol>\n<li>\n<p><strong>Get Authorization Code<\/strong>:<\/p>\n\n<ul>\n<li>Visit the following URL to get the authorization code:\n<\/li>\n<\/ul>\n<pre class=\"highlight plaintext\"><code> https:\/\/&lt;YOUR_COGNITO_DOMAIN&gt;\/oauth2\/authorize?response_type=code&amp;client_id=&lt;YOUR_CLIENT_ID&gt;&amp;redirect_uri=https:\/\/callback&amp;scope=openid+email+phone\n<\/code><\/pre>\n\n<\/li>\n<\/ol>\n\n<ul>\n<li>After sending the request, you'll be redirected to a callback URL. Pick the authorization code from the URL. This URL may be a non-existent page, so just get the code from the query parameters.<\/li>\n<\/ul>\n\n<p><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%2Frpq86xrm5fg693pvno42.png\" class=\"article-body-image-wrapper\"><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%2Frpq86xrm5fg693pvno42.png\" alt=\"Image description\" width=\"800\" height=\"110\"><\/a><\/p>\n\n<h3>\n  \n  \n  Step 2: Get Access Token\n<\/h3>\n\n<ol>\n<li>\n<p><strong>Request Access Token<\/strong>:<\/p>\n\n<ul>\n<li>Use the following <code>curl<\/code> command to exchange the authorization code for an access token:\n<\/li>\n<\/ul>\n<pre class=\"highlight shell\"><code> curl <span class=\"nt\">-X<\/span> POST <span class=\"s1\">'https:\/\/&lt;YOUR_COGNITO_DOMAIN&gt;\/oauth2\/token'<\/span> <span class=\"se\">\\<\/span>\n <span class=\"nt\">-H<\/span> <span class=\"s1\">'Content-Type: application\/x-www-form-urlencoded'<\/span> <span class=\"se\">\\<\/span>\n <span class=\"nt\">-d<\/span> <span class=\"s1\">'grant_type=authorization_code&amp;client_id=&lt;YOUR_CLIENT_ID&gt;&amp;code=YOUR_AUTH_CODE&amp;redirect_uri=https:\/\/callback'<\/span>\n<\/code><\/pre>\n\n<\/li>\n<\/ol>\n\n<ul>\n<li>Replace <code>YOUR_AUTH_CODE<\/code> with the code you obtained in the previous step.<\/li>\n<\/ul>\n\n<p><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%2Fjwj4pigfzu652ghrfzwx.png\" class=\"article-body-image-wrapper\"><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%2Fjwj4pigfzu652ghrfzwx.png\" alt=\"Image description\" width=\"800\" height=\"260\"><\/a><\/p>\n\n<h3>\n  \n  \n  Step 3: Test API Endpoints\n<\/h3>\n\n<ol>\n<li>\n<p><strong>Set Up Postman<\/strong>:<\/p>\n\n<ul>\n<li>Open Postman and create a new request.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Add Authorization Header<\/strong>:<\/p>\n\n<ul>\n<li>Use the access token obtained in Step 2 to set up the authorization header for each request:\n\n<ul>\n<li>Go to the \"Authorization\" tab in Postman.<\/li>\n<li>Select \"Bearer Token\" as the type.<\/li>\n<li>Paste the access token into the \"Token\" field.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n<p><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%2Fvgnnzk5clgg1pm6hbrih.png\" class=\"article-body-image-wrapper\"><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%2Fvgnnzk5clgg1pm6hbrih.png\" alt=\"Image description\" width=\"800\" height=\"185\"><\/a><\/p>\n\n<p>Go to your lambda console and get your api enpoints i.e in the configurations on the triggers tab<\/p>\n\n<ol>\n<li>\n<strong>Test Endpoints<\/strong>:<\/li>\n<\/ol>\n\n<ul>\n<li>\n<strong>GET <code>\/tasks<\/code><\/strong>:\n\n<ul>\n<li>Send a GET request to <code>https:\/\/yy045z23h0.execute-api.us-east-1.amazonaws.com\/prod\/tasks<\/code> to get all tasks by the user.<\/li>\n<li>\n<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%2Fmld7m1gxob742e3mfzjt.png\" alt=\"Image description\" width=\"800\" height=\"508\">\n<\/li>\n<\/ul>\n\n\n<\/li>\n\n<\/ul>\n\n<p><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%2Fhilkxq4zg4ajx7vjln3f.png\" class=\"article-body-image-wrapper\"><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%2Fhilkxq4zg4ajx7vjln3f.png\" alt=\"Image description\" width=\"800\" height=\"414\"><\/a><\/p>\n\n<ul>\n<li>\n<strong>POST <code>\/tasks<\/code><\/strong>:\n\n<ul>\n<li>Send a POST request to <code>https:\/\/yy045z23h0.execute-api.us-east-1.amazonaws.com\/prod\/tasks<\/code> with the task data in the body.<\/li>\n<li>\n<\/li>\n<\/ul>\n\n\n<\/li>\n\n<\/ul>\n\n<p><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%2Fkdc5xvy5xrkehmmdramp.png\" class=\"article-body-image-wrapper\"><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%2Fkdc5xvy5xrkehmmdramp.png\" alt=\"Image description\" width=\"800\" height=\"461\"><\/a><\/p>\n\n<ul>\n<li>\n<p><strong>GET <code>\/tasks\/{taskId}<\/code><\/strong>:<\/p>\n\n<ul>\n<li>Send a GET request to <code>https:\/\/yy045z23h0.execute-api.us-east-1.amazonaws.com\/prod\/tasks\/{taskId}<\/code> to retrieve a specific task.<\/li>\n<li>\n<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%2Frmwx1kxtta1dfejt9ruo.png\" alt=\"Image description\" width=\"800\" height=\"461\">\n<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\n<p><strong>PUT <code>\/tasks\/{taskId}<\/code><\/strong>:<\/p>\n\n<ul>\n<li>Send a PUT request to <code>https:\/\/yy045z23h0.execute-api.us-east-1.amazonaws.com\/prod\/tasks\/{taskId}<\/code> with the updated task data in the body.<\/li>\n<li>\n<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%2F84lg1csl9p3pl2vy85kz.png\" alt=\"Image description\" width=\"800\" height=\"461\">\n<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\n<p><strong>DELETE <code>\/tasks\/{taskId}<\/code><\/strong>:<\/p>\n\n<ul>\n<li>Send a DELETE request to <code>https:\/\/yy045z23h0.execute-api.us-east-1.amazonaws.com\/prod\/tasks\/{taskId}<\/code> to delete a specific task.\n-\n<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%2F67xc4d0m2ewnuq1xwiis.png\" alt=\"Image description\" width=\"800\" height=\"461\">\n<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\n<p><strong>Test Sending Reminders<\/strong>:<\/p>\n\n<ul>\n<li>Since the <code>\/send-reminders<\/code> function is triggered by a scheduled event (cron job), you cannot test it with Postman. Instead, you can test it by invoking the Lambda function manually from the AWS Lambda console or by checking CloudWatch logs.<\/li>\n<li>To test, go to the AWS Lambda console, select the Lambda function, and use the \"Test\" feature to simulate an invocation.<\/li>\n<li>\n<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%2F7etzrwl92nt6bp3hbeo6.png\" alt=\"Image description\" width=\"800\" height=\"402\">\n\n<ul>\n<li>\n<\/li>\n<\/ul>\n\n\n<\/li>\n\n<\/ul>\n\n<\/li>\n\n<\/ul>\n\n<p><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%2F5unw4o9jdnywziz9bt3i.png\" class=\"article-body-image-wrapper\"><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%2F5unw4o9jdnywziz9bt3i.png\" alt=\"Image description\" width=\"800\" height=\"402\"><\/a><\/p>\n\n<ul>\n<li>\n<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%2Fi1t7nazgb7s8hb5glnni.jpeg\" alt=\"Image description\" width=\"800\" height=\"487\">\n<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Scope and Grants\n<\/h3>\n\n<ul>\n<li>\n<strong>Scopes<\/strong>: We are using <code>openid<\/code>, <code>email<\/code>, and <code>phone<\/code>. You may include any other scopes as needed for your application.<\/li>\n<li>\n<strong>Grants<\/strong>: We are using both <code>authorization_code<\/code> and <code>implicit<\/code> grant types in our AWS Cognito settings.<\/li>\n<\/ul>\n\n<p>With these steps, you can effectively test the API endpoints of your Task Manager application using Postman. Ensure that you replace placeholders with your actual values and screenshots.<\/p>\n\n<h2>\n  \n  \n  Conclusion\n<\/h2>\n\n<p>In this tutorial, we've built and tested a serverless Task Manager application using AWS services and various technologies. Here's a summary of what we've accomplished:<\/p>\n\n<ol>\n<li>\n<p><strong>Serverless Architecture Setup<\/strong>:<\/p>\n\n<ul>\n<li>We created a serverless backend using AWS Lambda, API Gateway, and DynamoDB to manage CRUD operations for tasks.<\/li>\n<li>We utilized AWS Cognito for authentication, configuring both <code>authorization_code<\/code> and <code>implicit<\/code> grant types to handle user sign-ins securely.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>API Gateway Configuration<\/strong>:<\/p>\n\n<ul>\n<li>We set up API Gateway to handle various HTTP methods for the <code>\/tasks<\/code> resource, including GET, POST, PUT, and DELETE operations.<\/li>\n<li>We connected each API method to its corresponding Lambda function and secured the endpoints using AWS Cognito Authorizer.<\/li>\n<li>The API was deployed to a production stage to make it accessible for testing.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Testing the API<\/strong>:<\/p>\n\n<ul>\n<li>We demonstrated how to obtain an authorization code and exchange it for an access token using AWS Cognito.<\/li>\n<li>We tested the API endpoints with Postman, including operations to create, retrieve, update, and delete tasks. Each request was configured with the appropriate authorization token.<\/li>\n<li>For the <code>\/send-reminders<\/code> functionality, which is triggered by a scheduled event, we tested the Lambda function manually using the AWS Lambda console and reviewed the Lambda logs to ensure proper execution.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Reminder Functionality<\/strong>:<\/p>\n\n<ul>\n<li>We configured a Lambda function to send SMS reminders for tasks due on the current date using Twilio. This function was scheduled to run daily via CloudWatch Events.<\/li>\n<li>The testing for the reminder function was handled within the AWS Lambda console, given that it does not expose a direct API endpoint.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n<p>The code for all the functions used in this tutorial is accessible on <a href=\"https:\/\/github.com\/ki3ani\/TaskManagerFunctions\" rel=\"noopener noreferrer\">GitHub<\/a>. Feel free to explore the repository for detailed implementation and configuration.<\/p>\n\n<p>Stay tuned for more tutorials covering various aspects of backend development and cloud technologies. I'll be sharing insights and practical guides to help you build robust and scalable solutions using modern technologies. Happy coding!<\/p>\n\n","category":["aws","python","serverless","api"]},{"title":"Deploying Your First Dockerized Django REST API on AWS Elastic Beanstalk: A Comprehensive Guide","pubDate":"Tue, 23 May 2023 09:19:19 +0000","link":"https:\/\/dev.to\/ki3ani\/deploying-your-first-dockerized-django-rest-api-on-aws-elastic-beanstalk-a-comprehensive-guide-2m77","guid":"https:\/\/dev.to\/ki3ani\/deploying-your-first-dockerized-django-rest-api-on-aws-elastic-beanstalk-a-comprehensive-guide-2m77","description":"<p>Welcome to this comprehensive guide on deploying a Dockerized Django REST API on AWS Elastic Beanstalk. This tutorial is designed to walk you through the process, starting from setting up your Django application to finally deploying it on AWS Elastic Beanstalk.<\/p>\n\n<p>But first, let's take a moment to understand why this is important.<\/p>\n\n<p>In an increasingly digital world, web services and APIs play a crucial role in enabling seamless communication between different software applications. Among many frameworks, Django stands out for its robustness and simplicity, making it a preferred choice for many Python developers.<\/p>\n\n<p>Furthermore, Docker simplifies deployment by packaging applications with all their dependencies into standardized units called containers. This removes common issues such as \"it works on my machine but not on the server\" problem. This is why Dockerizing your Django REST API not only makes your project more manageable but also ensures it runs the same, regardless of the environment.<\/p>\n\n<p>AWS Elastic Beanstalk is a popular choice for deployment because it handles all the infrastructure details, letting you focus on just the application. It supports several platforms, including Docker, and automates the process of deployment, capacity provisioning, load balancing, and automatic scaling.<\/p>\n\n<p>By the end of this tutorial, you will have learned how to set up a Django REST API, Dockerize it, and deploy it on AWS Elastic Beanstalk. This guide is designed for developers who have a basic understanding of Django, Docker, and AWS, but are looking to piece everything together in a production-ready setup.<\/p>\n\n<p>In the next sections, we will delve deeper into each step, explain the concepts, provide code snippets, and show you exactly what you need to do. Let's dive in!<\/p>\n\n<h1>\n  \n  \n  1.Creating the API\n<\/h1>\n\n<h3>\n  \n  \n  Create a virtual environment:\n<\/h3>\n\n<p><code>virtualenv env<\/code><br>\n<code>source env\/bin\/activate<\/code><\/p>\n<h3>\n  \n  \n  Set up a new Django project\n<\/h3>\n\n<p>Firstly, we need to install Django and Django REST framework. Make sure you have Python installed on your machine. You can install Django and Django REST framework using pip:<\/p>\n\n<p><code>pip install django<\/code><br>\n<code>pip install djangorestframework<\/code><\/p>\n\n<p>Now, we can create a new Django project. Let's name it \"bookstore\":<\/p>\n\n<p><code>django-admin startproject bookstore<\/code><\/p>\n<h3>\n  \n  \n  Create a new Django app:\n<\/h3>\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"n\">cd<\/span> <span class=\"n\">bookstore<\/span>\n<span class=\"n\">python<\/span> <span class=\"n\">manage<\/span><span class=\"p\">.<\/span><span class=\"n\">py<\/span> <span class=\"n\">startapp<\/span> <span class=\"n\">books<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n<h3>\n  \n  \n  Define the Book model\n<\/h3>\n\n<p>In books\/models.py, define a Book model:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">django.db<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">models<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">Book<\/span><span class=\"p\">(<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">Model<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">title<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">CharField<\/span><span class=\"p\">(<\/span><span class=\"n\">max_length<\/span><span class=\"o\">=<\/span><span class=\"mi\">200<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">author<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">CharField<\/span><span class=\"p\">(<\/span><span class=\"n\">max_length<\/span><span class=\"o\">=<\/span><span class=\"mi\">100<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">publication_date<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">DateField<\/span><span class=\"p\">()<\/span>\n    <span class=\"n\">isbn<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">CharField<\/span><span class=\"p\">(<\/span><span class=\"n\">max_length<\/span><span class=\"o\">=<\/span><span class=\"mi\">20<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">summary<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">TextField<\/span><span class=\"p\">()<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Don't forget to add 'books' to installed apps in bookstore\/settings.py:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"n\">INSTALLED_APPS<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n    <span class=\"bp\">...<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">rest_framework<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">books<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">]<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Run migrations to create the corresponding database table:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"n\">python<\/span> <span class=\"n\">manage<\/span><span class=\"p\">.<\/span><span class=\"n\">py<\/span> <span class=\"n\">makemigrations<\/span>\n<span class=\"n\">python<\/span> <span class=\"n\">manage<\/span><span class=\"p\">.<\/span><span class=\"n\">py<\/span> <span class=\"n\">migrate<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Create a serializer for the Book model\n<\/h3>\n\n<p>In books\/serializers.py, define a BookSerializer:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">rest_framework<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">serializers<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">.models<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Book<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">BookSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">serializers<\/span><span class=\"p\">.<\/span><span class=\"n\">ModelSerializer<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">class<\/span> <span class=\"nc\">Meta<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">model<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Book<\/span>\n        <span class=\"n\">fields<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">'<\/span><span class=\"s\">__all__<\/span><span class=\"sh\">'<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Set up a view for handling REST API requests\n<\/h3>\n\n<p>In books\/views.py, define a BookViewSet:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">rest_framework<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">viewsets<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">.models<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Book<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">.serializers<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">BookSerializer<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">BookViewSet<\/span><span class=\"p\">(<\/span><span class=\"n\">viewsets<\/span><span class=\"p\">.<\/span><span class=\"n\">ModelViewSet<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">queryset<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Book<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">all<\/span><span class=\"p\">()<\/span>\n    <span class=\"n\">serializer_class<\/span> <span class=\"o\">=<\/span> <span class=\"n\">BookSerializer<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Configure the URL routing\n<\/h3>\n\n<p>In bookstore\/urls.py, add a route for the books application:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">django.urls<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">include<\/span><span class=\"p\">,<\/span> <span class=\"n\">path<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">rest_framework.routers<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">DefaultRouter<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">books.views<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">BookViewSet<\/span>\n\n<span class=\"n\">router<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">DefaultRouter<\/span><span class=\"p\">()<\/span>\n<span class=\"n\">router<\/span><span class=\"p\">.<\/span><span class=\"nf\">register<\/span><span class=\"p\">(<\/span><span class=\"sa\">r<\/span><span class=\"sh\">'<\/span><span class=\"s\">books<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">BookViewSet<\/span><span class=\"p\">)<\/span>\n\n<span class=\"n\">urlpatterns<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n    <span class=\"nf\">path<\/span><span class=\"p\">(<\/span><span class=\"sh\">''<\/span><span class=\"p\">,<\/span> <span class=\"nf\">include<\/span><span class=\"p\">(<\/span><span class=\"n\">router<\/span><span class=\"p\">.<\/span><span class=\"n\">urls<\/span><span class=\"p\">)),<\/span>\n<span class=\"p\">]<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Test the API locally\n<\/h3>\n\n<p>Start the Django development server:<\/p>\n\n<p><code>python manage.py runserver<\/code><\/p>\n\n<p>You should now be able to access the API at <a href=\"http:\/\/localhost:8000\/books\/\" rel=\"noopener noreferrer\">localhost<\/a> as shown:<\/p>\n\n<p><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%2Fhzm5iv42vyxms2ycahz7.png\" class=\"article-body-image-wrapper\"><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%2Fhzm5iv42vyxms2ycahz7.png\" alt=\"localhost\" width=\"800\" height=\"498\"><\/a><\/p>\n\n<blockquote>\n<p>Note the Local url meaning your api is running from your machine<\/p>\n<\/blockquote>\n\n<p>Awesome! With the Django RESTful API ready, the next step is to Dockerize your application<\/p>\n\n<h1>\n  \n  \n  2.Dockerising the API\n<\/h1>\n\n<h3>\n  \n  \n  Download Docker\n<\/h3>\n\n<p>We will use the CLI to download Docker, By using the Docker CLI, you empower yourself with a powerful toolset to interact with Docker, manage your containers, and orchestrate your applications effectively. It provides a consistent and flexible interface to work with Docker, whether you're running it locally or in cloud-based environments.<\/p>\n\n<p>For Linux:<br>\n<code>curl -fsSL https:\/\/get.docker.com -o get-docker.sh<\/code><br>\n<code>sudo sh get-docker.sh<\/code><\/p>\n\n<p>For MacOS:<br>\n<code>brew install --cask docker<\/code><\/p>\n\n<p>For Windows\/powershell:<br>\n<code>iex \"&amp; { $(irm https:\/\/aka.ms\/win-docker\/cli-latest.ps1) }\"<\/code><\/p>\n\n<p><em>Use this command to get Docker running on your System<\/em>:<br>\n<code>sudo systemctl start docker<\/code><\/p>\n<h3>\n  \n  \n  Creating a Dockerfile:\n<\/h3>\n\n<p>Create a new file in your project's root directory (the same directory where manage.py is located) and name it Dockerfile. This file will define how to build the Docker image for your application. Here's a basic Dockerfile for a Django application:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight docker\"><code><span class=\"c\"># Use an official Python runtime as a parent image<\/span>\n<span class=\"k\">FROM<\/span><span class=\"s\"> python:3.9-slim-buster<\/span>\n\n<span class=\"c\"># Set environment variables<\/span>\n<span class=\"k\">ENV<\/span><span class=\"s\"> PYTHONDONTWRITEBYTECODE 1<\/span>\n<span class=\"k\">ENV<\/span><span class=\"s\"> PYTHONUNBUFFERED 1<\/span>\n\n<span class=\"c\"># Set the working directory in the container to \/app<\/span>\n<span class=\"k\">WORKDIR<\/span><span class=\"s\"> \/app<\/span>\n\n<span class=\"c\"># Add the current directory files (on your machine) to the container<\/span>\n<span class=\"k\">ADD<\/span><span class=\"s\"> . \/app\/<\/span>\n\n<span class=\"c\"># Install any needed packages specified in requirements.txt<\/span>\n<span class=\"k\">RUN <\/span>pip <span class=\"nb\">install<\/span> <span class=\"nt\">--upgrade<\/span> pip\n<span class=\"k\">RUN <\/span>pip <span class=\"nb\">install<\/span> <span class=\"nt\">-r<\/span> requirements.txt\n\n<span class=\"c\"># Expose the port server is running on<\/span>\n<span class=\"k\">EXPOSE<\/span><span class=\"s\"> 8000<\/span>\n\n<span class=\"c\"># Start the server<\/span>\n<span class=\"k\">CMD<\/span><span class=\"s\"> [\"python\", \"manage.py\", \"runserver\", \"0.0.0.0:8000\"]<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<blockquote>\n<p>The Dockerfile provides instructions for building a Docker image for a Django application. It starts with an official Python 3.9 slim image as the base. Environment variables are set to disable bytecode writing and enable unbuffered output.<br>\nThe working directory is set to \/app, and the current directory's files are added to the container. The requirements.txt file is used to install the necessary Python packages.<br>\nPort 8000 is exposed to allow incoming connections. Finally, the Django development server is started with the command python manage.py runserver 0.0.0.0:8000.<br>\nThis Dockerfile allows you to package your Django application and its dependencies into a container, making it portable and easily deployable across different environments.<\/p>\n<\/blockquote>\n\n<h3>\n  \n  \n  Create a requirements.txt file\n<\/h3>\n\n<p>You also need to create a requirements.txt file that lists the Python dependencies of your project so that Docker can install them. You can generate a requirements.txt using :<\/p>\n\n<p><code>pip freeze &gt; requirements.txt<\/code><\/p>\n\n<h3>\n  \n  \n  Build the Docker image\n<\/h3>\n\n<p>Now you can build the Docker image from the Dockerfile. Make sure Docker Desktop is running, and then run the following command in the terminal from the directory that contains the Dockerfile:<\/p>\n\n<p><code>docker build -t bookstore .<\/code><\/p>\n\n<p>You can use this command to look at your new Django Image:<br>\n<code>docker images<\/code><\/p>\n<h3>\n  \n  \n  Run the application using Docker:\n<\/h3>\n\n<p>'docker run -p 8000:8000 bookstore'<\/p>\n\n<blockquote>\n<p>You may get a DisallowedHost error which occurs because the ALLOWED_HOSTS setting in your Django project is not configured to allow the given host value '0.0.0.0'.To fix this issue, you can update the ALLOWED_HOSTS setting in your Django project to include '0.0.0.0'<\/p>\n<\/blockquote>\n\n<p>You should now be able to access the API at <a href=\"http:\/\/0.0.0.0:8000\/\" rel=\"noopener noreferrer\">http:\/\/0.0.0.0:8000\/<\/a> again, this time running inside a Docker container as shown:<\/p>\n\n<p><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%2F8yd155k3k633m8bp7658.png\" class=\"article-body-image-wrapper\"><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%2F8yd155k3k633m8bp7658.png\" alt=\"Docker Dep\" width=\"800\" height=\"498\"><\/a><\/p>\n\n<blockquote>\n<p>Note the new url which your api is now running as a Docker container<\/p>\n<\/blockquote>\n\n<p>Now your application is Dockerized and ready to be deployed to AWS Elastic Beanstalk.<\/p>\n<h1>\n  \n  \n  3.Deploying Dockerised API on AWS Elastic Beanstalk\n<\/h1>\n\n<p>Before deploying your app you need to ensure that you have an Dockerhub account which is a cloud-based registry service that allows you to link to code repositories, build your images and test them, store manually pushed images, and link to Docker Cloud so you can deploy images to your hosts. It provides a centralized resource for container image discovery, distribution, change management, and collaboration.<\/p>\n\n<p>After making your account, You can now login using the CLI:<\/p>\n\n<p><code>docker login<\/code><\/p>\n\n<blockquote>\n<p>It will ask for your Docker Hub username and password.<\/p>\n<\/blockquote>\n\n<p>Tag your image with your Docker Hub username. Docker requires that the image you're pushing includes your Docker Hub username. Use the command:<br>\n<code>docker tag bookstore:latest &lt;your-docker-hub<br>\nusername&gt;\/nice-reads:latest<\/code><\/p>\n\n<blockquote>\n<p>NB: I called my Dockerhub repo nice-reads but you can name it anything you prefer also i have just left the default tag which is latest<\/p>\n<\/blockquote>\n\n<p>Next, After tagging the image, you can push it to Docker Hub using the command:<br>\n<code>docker push &lt;your-docker-hub-username&gt;\/nice-reads:latest<\/code><\/p>\n\n<blockquote>\n<p>Please ensure that you replace  with your Docker Hub username in the commands above.<\/p>\n<\/blockquote>\n\n<p>Great, now that you've pushed your Docker image to Docker Hub, you can deploy it to AWS Elastic Beanstalk.<\/p>\n\n<p>Install the Elastic Beanstalk Command Line Interface (EB CLI) if you haven't done so yet. You can install it with pip:<\/p>\n\n<p><code>pip install awsebcli<\/code><\/p>\n\n<p>Initialize your Elastic Beanstalk environment. In the root of your project, run:<\/p>\n\n<p><code>eb init<\/code><\/p>\n\n<blockquote>\n<p>You'll be prompted to select a region, and to provide your AWS Access Key ID and Secret Access Key. If you haven't created these yet, you can create them in the AWS IAM Console. You'll also be asked to choose a platform; you can choose Docker.<\/p>\n<\/blockquote>\n\n<p>Next, Create a Dockerrun.aws.json file in the root of your project. This file is required by AWS Elastic Beanstalk to understand how to run your Docker container. Here is an example of what the file can look like:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight json\"><code><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"AWSEBDockerrunVersion\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"1\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"Image\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"Name\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"&lt;your-docker-hub-username&gt;\/nice-reads:latest\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"Update\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"true\"<\/span><span class=\"w\">\n  <\/span><span class=\"p\">},<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"Ports\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"w\">\n    <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"ContainerPort\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"8000\"<\/span><span class=\"w\">\n    <\/span><span class=\"p\">}<\/span><span class=\"w\">\n  <\/span><span class=\"p\">]<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p>With the Dockerrun.aws.json file in place, you can create your Elastic Beanstalk environment:<\/p>\n\n<p><code>eb create<\/code><\/p>\n\n<blockquote>\n<p>The eb create command will ask you for an environment name and a CNAME prefix. The environment name is just a name for you to identify the environment, and the CNAME prefix is used to create a URL to your application.<br>\nAWS Elastic Beanstalk will then create an environment for your application with a load balancer, Auto Scaling group, security group, an Amazon S3 bucket for storing your application versions and logs, and CloudWatch alarms that monitor the health of your environment and trigger automatic scaling actions.<br>\nIt will also pull the Docker image from Docker Hub and run it.<\/p>\n<\/blockquote>\n\n<p>After the command completes, your application should be accessible on the internet. You can get the URL with the command:<\/p>\n\n<p><code>eb open<\/code><\/p>\n\n<p>This will open our deployed API via the url as shown:<\/p>\n\n<p><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%2Fixrp2xwokrltbxydmc0h.png\" class=\"article-body-image-wrapper\"><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%2Fixrp2xwokrltbxydmc0h.png\" alt=\"Eb open\" width=\"800\" height=\"498\"><\/a><\/p>\n\n<blockquote>\n<p>Note the new url that confirms deployment<\/p>\n<\/blockquote>\n\n<p>Finally you can check the status of you application on Eb by running this command:<\/p>\n\n<p><code>eb status<\/code><\/p>\n\n<p>Which should look similar to this:<\/p>\n\n<p><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%2F3k0lz608pwk8j2o6i7dp.png\" class=\"article-body-image-wrapper\"><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%2F3k0lz608pwk8j2o6i7dp.png\" alt=\"Status\" width=\"784\" height=\"196\"><\/a><\/p>\n\n<blockquote>\n<p>NB:if you are facing deployment issues related to ALLOWED_HOSTS, you may use ['*'] as a temporary measure, but do not forget to replace it with the actual hostname when moving to production.<\/p>\n<\/blockquote>\n\n<h1>\n  \n  \n  Conclusion\n<\/h1>\n\n<p>Congratulations! If you've followed along this tutorial, you have successfully deployed your Dockerized Django REST API to AWS Elastic Beanstalk. You can now navigate to your app's URL and enjoy the fully functional, live application.<\/p>\n\n<p>It's worth checking the status of your environment on the Elastic Beanstalk console. If you see a green checkmark and a status of \"Healthy,\" that means your application is running smoothly.<\/p>\n\n<p>Remember that you can also keep track of your AWS usage and manage costs by visiting the Billing &amp; Cost Management Dashboard on your AWS console. This is especially important if you're working on large-scale projects or using multiple AWS services.<br>\nWhile there are numerous ways to deploy applications to AWS Elastic Beanstalk, we opted to use the AWS CLI throughout this tutorial. The AWS CLI is a powerful tool that allows you to manage your AWS services from the command line, providing a consistent interface across services. It's also worth noting that this approach enables you to automate processes through scripts, thereby enhancing productivity and reducing manual errors.<br>\nTo make all this work, you need to have properly configured your AWS account, which includes setting up IAM roles and permissions. AWS provides comprehensive guides on their website to help you navigate these configuration settings.<\/p>\n\n<p>The Django REST API application used in this tutorial is available on my GitHub repository<a href=\"https:\/\/github.com\/ki3ani\/mybookapp\" rel=\"noopener noreferrer\">BookstoreApp<\/a>. Feel free to clone it, explore it, and use it as a foundation for your own projects.<\/p>\n\n<p>In the journey of software development, remember that learning is continuous and the technology landscape is ever-evolving. Today, you've taken a significant step by learning how to deploy a Dockerized Django application on AWS Elastic Beanstalk. Keep exploring, keep learning, and most importantly, enjoy the process. Until next time, happy coding!<\/p>\n\n","category":["api","docker","aws","django"]},{"title":"Implementing JWT Authentication and User Profile with Django Rest API Part 3","pubDate":"Mon, 17 Apr 2023 22:12:02 +0000","link":"https:\/\/dev.to\/ki3ani\/implementing-jwt-authentication-and-user-profile-with-django-rest-api-part-3-3dh9","guid":"https:\/\/dev.to\/ki3ani\/implementing-jwt-authentication-and-user-profile-with-django-rest-api-part-3-3dh9","description":"<h2>\n  \n  \n  Introduction\n<\/h2>\n\n<p>Welcome back to part three of our React and Django series, where we're creating a Notes app from scratch. As we know, security is of utmost importance in any web application, and authentication is a crucial aspect of it. This is where JWT comes in. JSON Web Tokens (JWT) is a widely used standard for securely transmitting information between parties as a JSON object. JWT allows us to authenticate users and secure our application by encrypting and transmitting user data in the form of a token. It's a great option for authentication because it allows us to store user information directly in the token, making it easy to verify the user's identity with every subsequent request. In this post, we'll be implementing JWT authentication to ensure that our users' data stays safe and secure. So, let's dive in and learn how to secure our Notes app with JWT authentication<\/p>\n\n<h3>\n  \n  \n  Installing Neccessary Packages\n<\/h3>\n\n<p>Before we start off we need to install the necessary django packages required for JWT these are:<\/p>\n\n<p><code>pip install djangorestframework-simplejwt<\/code><br>\nThe djangorestframework-simplejwt package provides a simple way to implement JWT authentication in Django REST framework applications. It includes views and serializers for generating and refreshing JWT tokens, as well as a built-in token authentication backend for validating tokens.<\/p>\n\n<p>Next we can then include it in the installed apps and add it to the settings:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"n\">INSTALLED_APPS<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n\n\n    <span class=\"sh\">'<\/span><span class=\"s\">rest_framework_simplejwt.token_blacklist<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">]<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Token blacklisting involves maintaining a list of tokens that have been revoked or expired, and checking each incoming token against this list to ensure that it is still valid. This can help to prevent security vulnerabilities, such as token theft or replay attacks.<\/p>\n\n<p>Next,we setup the JWT:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"n\">SIMPLE_JWT<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">ACCESS_TOKEN_LIFETIME<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"nf\">timedelta<\/span><span class=\"p\">(<\/span><span class=\"n\">minutes<\/span><span class=\"o\">=<\/span><span class=\"mi\">180<\/span><span class=\"p\">),<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">REFRESH_TOKEN_LIFETIME<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"nf\">timedelta<\/span><span class=\"p\">(<\/span><span class=\"n\">days<\/span><span class=\"o\">=<\/span><span class=\"mi\">50<\/span><span class=\"p\">),<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">ROTATE_REFRESH_TOKENS<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"bp\">True<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">BLACKLIST_AFTER_ROTATION<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"bp\">True<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">UPDATE_LAST_LOGIN<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"bp\">False<\/span><span class=\"p\">,<\/span>\n\n    <span class=\"sh\">'<\/span><span class=\"s\">ALGORITHM<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">HS256<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n\n    <span class=\"sh\">'<\/span><span class=\"s\">VERIFYING_KEY<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"bp\">None<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">AUDIENCE<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"bp\">None<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">ISSUER<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"bp\">None<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">JWK_URL<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"bp\">None<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">LEEWAY<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span>\n\n    <span class=\"sh\">'<\/span><span class=\"s\">AUTH_HEADER_TYPES<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">Bearer<\/span><span class=\"sh\">'<\/span><span class=\"p\">,),<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">AUTH_HEADER_NAME<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">HTTP_AUTHORIZATION<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">USER_ID_FIELD<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">id<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">USER_ID_CLAIM<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">user_id<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">USER_AUTHENTICATION_RULE<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">rest_framework_simplejwt.authentication.default_user_authentication_rule<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n\n    <span class=\"sh\">'<\/span><span class=\"s\">AUTH_TOKEN_CLASSES<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">rest_framework_simplejwt.tokens.AccessToken<\/span><span class=\"sh\">'<\/span><span class=\"p\">,),<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">TOKEN_TYPE_CLAIM<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">token_type<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">TOKEN_USER_CLASS<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">rest_framework_simplejwt.models.TokenUser<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n\n    <span class=\"sh\">'<\/span><span class=\"s\">JTI_CLAIM<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">jti<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n\n    <span class=\"sh\">'<\/span><span class=\"s\">SLIDING_TOKEN_REFRESH_EXP_CLAIM<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">refresh_exp<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">SLIDING_TOKEN_LIFETIME<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"nf\">timedelta<\/span><span class=\"p\">(<\/span><span class=\"n\">minutes<\/span><span class=\"o\">=<\/span><span class=\"mi\">5<\/span><span class=\"p\">),<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">SLIDING_TOKEN_REFRESH_LIFETIME<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"nf\">timedelta<\/span><span class=\"p\">(<\/span><span class=\"n\">days<\/span><span class=\"o\">=<\/span><span class=\"mi\">1<\/span><span class=\"p\">),<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Here is an explanation of some of the key settings:<\/p>\n\n<p>ACCESS_TOKEN_LIFETIME: This sets the lifetime of the access token, which is the token that grants access to protected resources. In this case, it is set to 180 minutes (or 3 hours).<\/p>\n\n<p>REFRESH_TOKEN_LIFETIME: This sets the lifetime of the refresh token, which is used to obtain a new access token after the original token expires. In this case, it is set to 50 days.<\/p>\n\n<p>ROTATE_REFRESH_TOKENS: This setting controls whether or not refresh tokens are rotated when a new access token is issued. If it is set to True, a new refresh token will be issued with each new access token.<\/p>\n\n<p>BLACKLIST_AFTER_ROTATION: This setting controls whether or not refresh tokens that have been rotated are blacklisted. If it is set to True, any previous refresh tokens will be invalidated when a new one is issued.<\/p>\n\n<p>ALGORITHM: This sets the algorithm used to sign the JWT tokens. In this case, it is set to HS256, which is a symmetric-key algorithm that uses a shared secret key to sign and verify tokens.<\/p>\n\n<p>AUTH_HEADER_TYPES: This specifies the types of authentication headers that can be used to send JWT tokens. In this case, it is set to ('Bearer',) which is the most commonly used type.<\/p>\n\n<p>AUTH_HEADER_NAME: This sets the name of the HTTP header that will be used to send the authentication token. In this case, it is set to 'HTTP_AUTHORIZATION'.<\/p>\n\n<p>USER_ID_FIELD: This sets the name of the field that will be used to identify the user in the JWT token. In this case, it is set to 'id'.<\/p>\n\n<p>USER_ID_CLAIM: This sets the name of the claim that will be used to store the user ID in the JWT token. In this case, it is set to 'user_id'.<\/p>\n\n<p>AUTH_TOKEN_CLASSES: This sets the classes of authentication tokens that will be accepted by the authentication system. In this case, it is set to ('rest_framework_simplejwt.tokens.AccessToken',) which is the default token class.<\/p>\n\n<p>JTI_CLAIM: This sets the name of the claim that will be used to store the unique identifier of the JWT token. In this case, it is set to 'jti'.<\/p>\n\n<h3>\n  \n  \n  Configuring the urls\n<\/h3>\n\n<p>Now that we have configured the settings, we can now move to configuring our authentication urls, where we will we will create the URL for access token and refresh token in the app level since we are only authenticating one app:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"n\">urlpatterns<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n    <span class=\"c1\">#Authentication\n<\/span>    <span class=\"nf\">path<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">token\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">views<\/span><span class=\"p\">.<\/span><span class=\"n\">MyTokenObtainPairView<\/span><span class=\"p\">.<\/span><span class=\"nf\">as_view<\/span><span class=\"p\">(),<\/span> <span class=\"n\">name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">token_obtain_pair<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n    <span class=\"nf\">path<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">token\/refresh\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">TokenRefreshView<\/span><span class=\"p\">.<\/span><span class=\"nf\">as_view<\/span><span class=\"p\">(),<\/span> <span class=\"n\">name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">token_refresh<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n<span class=\"p\">]<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Great now that we have that setup we can create a Profile for our Notes app users such that only authenticated users have access to the app.We can do that by first:<\/p>\n\n<ol>\n<li>\n<strong>Creating User Model<\/strong>\n<\/li>\n<\/ol>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">django.contrib.auth.models<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">AbstractUser<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">CustomUser<\/span><span class=\"p\">(<\/span><span class=\"n\">AbstractUser<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">bio<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">CharField<\/span><span class=\"p\">(<\/span><span class=\"n\">max_length<\/span><span class=\"o\">=<\/span><span class=\"mi\">255<\/span><span class=\"p\">,<\/span> <span class=\"n\">blank<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">cover_photo<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">ImageField<\/span><span class=\"p\">(<\/span><span class=\"n\">upload_to<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">covers\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">null<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span> <span class=\"n\">blank<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>By creating a custom user model that extends AbstractUser, you can add fields that are specific to your application and provide additional functionality beyond what is available in the default User model.<\/p>\n\n<p>2.<strong>Updating our original Note Model<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, null=True, blank=True, related_name='notes')\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>This line of code defines a foreign key relationship between the Note model and the CustomUser model. The ForeignKey field creates a many-to-one relationship between Note and CustomUser, meaning that each Note is associated with a single CustomUser instance, but a CustomUser can have many Note instances.<\/p>\n\n<p>3.**Creating Views for UserProfile, Register and Login<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\">#Login User\n<\/span><span class=\"k\">class<\/span> <span class=\"nc\">MyTokenObtainPairView<\/span><span class=\"p\">(<\/span><span class=\"n\">TokenObtainPairView<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">serializer_class<\/span> <span class=\"o\">=<\/span> <span class=\"n\">MyTokenObtainPairSerializer<\/span>\n\n<span class=\"c1\">#Register User\n<\/span><span class=\"k\">class<\/span> <span class=\"nc\">RegisterView<\/span><span class=\"p\">(<\/span><span class=\"n\">generics<\/span><span class=\"p\">.<\/span><span class=\"n\">CreateAPIView<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">queryset<\/span> <span class=\"o\">=<\/span> <span class=\"n\">CustomUser<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">all<\/span><span class=\"p\">()<\/span>\n    <span class=\"n\">permission_classes<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"n\">AllowAny<\/span><span class=\"p\">,)<\/span>\n    <span class=\"n\">serializer_class<\/span> <span class=\"o\">=<\/span> <span class=\"n\">RegisterSerializer<\/span>\n\n<span class=\"c1\">#api\/profile  and api\/profile\/update\n<\/span><span class=\"nd\">@api_view<\/span><span class=\"p\">([<\/span><span class=\"sh\">'<\/span><span class=\"s\">GET<\/span><span class=\"sh\">'<\/span><span class=\"p\">])<\/span>\n<span class=\"nd\">@permission_classes<\/span><span class=\"p\">([<\/span><span class=\"n\">IsAuthenticated<\/span><span class=\"p\">])<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">getProfile<\/span><span class=\"p\">(<\/span><span class=\"n\">request<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">user<\/span> <span class=\"o\">=<\/span> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">user<\/span>\n    <span class=\"n\">serializer<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">ProfileSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">user<\/span><span class=\"p\">,<\/span> <span class=\"n\">many<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">(<\/span><span class=\"n\">serializer<\/span><span class=\"p\">.<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n\n<span class=\"nd\">@api_view<\/span><span class=\"p\">([<\/span><span class=\"sh\">'<\/span><span class=\"s\">PUT<\/span><span class=\"sh\">'<\/span><span class=\"p\">])<\/span>\n<span class=\"nd\">@permission_classes<\/span><span class=\"p\">([<\/span><span class=\"n\">IsAuthenticated<\/span><span class=\"p\">])<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">updateProfile<\/span><span class=\"p\">(<\/span><span class=\"n\">request<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">user<\/span> <span class=\"o\">=<\/span> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">user<\/span>\n    <span class=\"n\">serializer<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">ProfileSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">user<\/span><span class=\"p\">,<\/span> <span class=\"n\">data<\/span><span class=\"o\">=<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">data<\/span><span class=\"p\">,<\/span> <span class=\"n\">partial<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">if<\/span> <span class=\"n\">serializer<\/span><span class=\"p\">.<\/span><span class=\"nf\">is_valid<\/span><span class=\"p\">():<\/span>\n        <span class=\"n\">serializer<\/span><span class=\"p\">.<\/span><span class=\"nf\">save<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">(<\/span><span class=\"n\">serializer<\/span><span class=\"p\">.<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\">#api\/notes\n<\/span><span class=\"nd\">@api_view<\/span><span class=\"p\">([<\/span><span class=\"sh\">'<\/span><span class=\"s\">GET<\/span><span class=\"sh\">'<\/span><span class=\"p\">])<\/span>\n<span class=\"nd\">@permission_classes<\/span><span class=\"p\">([<\/span><span class=\"n\">IsAuthenticated<\/span><span class=\"p\">])<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">getNotes<\/span><span class=\"p\">(<\/span><span class=\"n\">request<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">public_notes<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Note<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">filter<\/span><span class=\"p\">(<\/span><span class=\"n\">is_public<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">).<\/span><span class=\"nf\">order_by<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">-updated<\/span><span class=\"sh\">'<\/span><span class=\"p\">)[:<\/span><span class=\"mi\">10<\/span><span class=\"p\">]<\/span>\n    <span class=\"n\">user_notes<\/span> <span class=\"o\">=<\/span> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">user<\/span><span class=\"p\">.<\/span><span class=\"n\">notes<\/span><span class=\"p\">.<\/span><span class=\"nf\">all<\/span><span class=\"p\">().<\/span><span class=\"nf\">order_by<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">-updated<\/span><span class=\"sh\">'<\/span><span class=\"p\">)[:<\/span><span class=\"mi\">10<\/span><span class=\"p\">]<\/span>\n    <span class=\"n\">notes<\/span> <span class=\"o\">=<\/span> <span class=\"n\">public_notes<\/span> <span class=\"o\">|<\/span> <span class=\"n\">user_notes<\/span>\n    <span class=\"n\">serializer<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">NoteSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">notes<\/span><span class=\"p\">,<\/span> <span class=\"n\">many<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">(<\/span><span class=\"n\">serializer<\/span><span class=\"p\">.<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The first code defines a custom token obtain view that uses a custom serializer for obtaining a JSON Web Token (JWT) pair for a user.<\/p>\n\n<p>The second code defines a view for registering a new user. It uses the built-in Django CreateAPIView and sets the permission class to AllowAny, which means anyone can access this view.<\/p>\n\n<p>The next two codes define views for getting and updating the user's profile. The getProfile view returns the serialized data for the currently authenticated user's profile, while the updateProfile view updates the profile with the data in the request. Both views require the user to be authenticated with the IsAuthenticated permission class.<\/p>\n\n<p>Finally, the last code defines a view for getting the user's notes. It first filters public notes and then the user's notes before combining them and returning them in serialized formThe first code defines a custom token obtain view that uses a custom serializer for obtaining a JSON Web Token (JWT) pair for a user.<br>\nThe second code defines a view for registering a new user. It uses the built-in Django CreateAPIView and sets the permission class to AllowAny, which means anyone can access this view.<br>\nThe next two codes define views for getting and updating the user's profile. The getProfile view returns the serialized data for the currently authenticated user's profile, while the updateProfile view updates the profile with the data in the request. Both views require the user to be authenticated with the IsAuthenticated permission class.<br>\nFinally, the last code defines a view for getting the user's notes. It first filters public notes and then the user's notes before combining them and returning them in serialized form. This view also requires the user to be authenticated with the IsAuthenticated permission class.. This view also requires the user to be authenticated with the IsAuthenticated permission class.<\/p>\n\n<ol>\n<li>\n<strong>Adding our Serializers<\/strong>\n<\/li>\n<\/ol>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">class<\/span> <span class=\"nc\">MyTokenObtainPairSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">TokenObtainPairSerializer<\/span><span class=\"p\">):<\/span>\n    <span class=\"nd\">@classmethod<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">get_token<\/span><span class=\"p\">(<\/span><span class=\"n\">cls<\/span><span class=\"p\">,<\/span> <span class=\"n\">user<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">token<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">super<\/span><span class=\"p\">().<\/span><span class=\"nf\">get_token<\/span><span class=\"p\">(<\/span><span class=\"n\">user<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"c1\"># Add custom claims\n<\/span>        <span class=\"n\">token<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">username<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">user<\/span><span class=\"p\">.<\/span><span class=\"n\">username<\/span>\n        <span class=\"n\">token<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">email<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">user<\/span><span class=\"p\">.<\/span><span class=\"n\">email<\/span>\n        <span class=\"c1\"># ...\n<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">token<\/span>\n\n\n<span class=\"k\">class<\/span> <span class=\"nc\">RegisterSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">serializers<\/span><span class=\"p\">.<\/span><span class=\"n\">ModelSerializer<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">password<\/span> <span class=\"o\">=<\/span> <span class=\"n\">serializers<\/span><span class=\"p\">.<\/span><span class=\"nc\">CharField<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">write_only<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span> <span class=\"n\">required<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span> <span class=\"n\">validators<\/span><span class=\"o\">=<\/span><span class=\"p\">[<\/span><span class=\"n\">validate_password<\/span><span class=\"p\">])<\/span>\n    <span class=\"n\">password2<\/span> <span class=\"o\">=<\/span> <span class=\"n\">serializers<\/span><span class=\"p\">.<\/span><span class=\"nc\">CharField<\/span><span class=\"p\">(<\/span><span class=\"n\">write_only<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span> <span class=\"n\">required<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">email<\/span> <span class=\"o\">=<\/span> <span class=\"n\">serializers<\/span><span class=\"p\">.<\/span><span class=\"nc\">EmailField<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">required<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">validators<\/span><span class=\"o\">=<\/span><span class=\"p\">[<\/span><span class=\"nc\">UniqueValidator<\/span><span class=\"p\">(<\/span><span class=\"n\">queryset<\/span><span class=\"o\">=<\/span><span class=\"n\">CustomUser<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">all<\/span><span class=\"p\">())]<\/span>\n    <span class=\"p\">)<\/span>\n\n    <span class=\"k\">class<\/span> <span class=\"nc\">Meta<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">model<\/span> <span class=\"o\">=<\/span> <span class=\"n\">CustomUser<\/span>\n        <span class=\"n\">fields<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">username<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">email<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">password<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">password2<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">bio<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">cover_photo<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">validate<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">attrs<\/span><span class=\"p\">):<\/span>\n        <span class=\"k\">if<\/span> <span class=\"n\">attrs<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">password<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span> <span class=\"o\">!=<\/span> <span class=\"n\">attrs<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">password2<\/span><span class=\"sh\">'<\/span><span class=\"p\">]:<\/span>\n            <span class=\"k\">raise<\/span> <span class=\"n\">serializers<\/span><span class=\"p\">.<\/span><span class=\"nc\">ValidationError<\/span><span class=\"p\">(<\/span>\n                <span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">password<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">Password fields didn<\/span><span class=\"sh\">'<\/span><span class=\"s\">t match.<\/span><span class=\"sh\">\"<\/span><span class=\"p\">})<\/span>\n\n        <span class=\"k\">return<\/span> <span class=\"n\">attrs<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">create<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">validated_data<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">user<\/span> <span class=\"o\">=<\/span> <span class=\"n\">CustomUser<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">create<\/span><span class=\"p\">(<\/span>\n            <span class=\"n\">username<\/span><span class=\"o\">=<\/span><span class=\"n\">validated_data<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">username<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n            <span class=\"n\">email<\/span><span class=\"o\">=<\/span><span class=\"n\">validated_data<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">email<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n            <span class=\"n\">bio<\/span><span class=\"o\">=<\/span><span class=\"n\">validated_data<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">bio<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n            <span class=\"n\">cover_photo<\/span><span class=\"o\">=<\/span><span class=\"n\">validated_data<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">cover_photo<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n        <span class=\"p\">)<\/span>\n\n        <span class=\"n\">user<\/span><span class=\"p\">.<\/span><span class=\"nf\">set_password<\/span><span class=\"p\">(<\/span><span class=\"n\">validated_data<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">password<\/span><span class=\"sh\">'<\/span><span class=\"p\">])<\/span>\n        <span class=\"n\">user<\/span><span class=\"p\">.<\/span><span class=\"nf\">save<\/span><span class=\"p\">()<\/span>\n\n        <span class=\"k\">return<\/span> <span class=\"n\">user<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">ProfileSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">serializers<\/span><span class=\"p\">.<\/span><span class=\"n\">ModelSerializer<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">notes<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">NoteSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">many<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span> <span class=\"n\">read_only<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">class<\/span> <span class=\"nc\">Meta<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">model<\/span> <span class=\"o\">=<\/span> <span class=\"n\">CustomUser<\/span>\n        <span class=\"n\">fields<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">'<\/span><span class=\"s\">__all__<\/span><span class=\"sh\">'<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>MyTokenObtainPairSerializer: a subclass of TokenObtainPairSerializer that adds custom claims (username, email, etc.) to the token payload.<br>\nRegisterSerializer: a serializer for the user registration process. It validates the password fields, checks for duplicate emails, and creates a new CustomUser instance if all fields are valid.<br>\nProfileSerializer: a serializer for the user profile data. It includes all fields from the CustomUser model and also serializes the related notes using NoteSerializer.<\/p>\n\n<ol>\n<li>** Configuring URL's **\n<\/li>\n<\/ol>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\">#Authentication\n<\/span><span class=\"nf\">path<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">token\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">views<\/span><span class=\"p\">.<\/span><span class=\"n\">MyTokenObtainPairView<\/span><span class=\"p\">.<\/span><span class=\"nf\">as_view<\/span><span class=\"p\">(),<\/span> <span class=\"n\">name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">token_obtain_pair<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n<span class=\"nf\">path<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">token\/refresh\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">TokenRefreshView<\/span><span class=\"p\">.<\/span><span class=\"nf\">as_view<\/span><span class=\"p\">(),<\/span> <span class=\"n\">name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">token_refresh<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n<span class=\"nf\">path<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">register\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">views<\/span><span class=\"p\">.<\/span><span class=\"n\">RegisterView<\/span><span class=\"p\">.<\/span><span class=\"nf\">as_view<\/span><span class=\"p\">(),<\/span> <span class=\"n\">name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">auth_register<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n\n<span class=\"c1\">#Profile\n<\/span><span class=\"nf\">path<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">profile\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">views<\/span><span class=\"p\">.<\/span><span class=\"n\">getProfile<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">profile<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n<span class=\"nf\">path<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">profile\/update\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">views<\/span><span class=\"p\">.<\/span><span class=\"n\">updateProfile<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">update-profile<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<blockquote>\n<p>NB: I haven't included the Note url because I explained it in part one of the series<\/p>\n<\/blockquote>\n\n<p>Okay Great with this steps done, we can now test whether our back-end is working as expected but first we need to apply migrations as we have created and modified our tables:<\/p>\n\n<p><code>python manage.py makemigrations<\/code><br>\n<code>python manage.py migrate<\/code><\/p>\n\n<h3>\n  \n  \n  Testing our Backend with Postman\n<\/h3>\n\n<p>Lets now test our backend using Postman,Postman is a popular software application that allows developers to test and debug APIs. With Postman, developers can send HTTP requests to a web server and view the response. <\/p>\n\n<ol>\n<li><strong>Registering Our User<\/strong><\/li>\n<\/ol>\n\n<p><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%2Fz9cdmx4snd7sxipb99ds.png\" class=\"article-body-image-wrapper\"><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%2Fz9cdmx4snd7sxipb99ds.png\" alt=\"Register User\" width=\"800\" height=\"377\"><\/a><\/p>\n\n<blockquote>\n<p>we make a POST request to 'api\/register\/' to create a new user <\/p>\n<\/blockquote>\n\n<p>2.<strong>Logging in<\/strong><\/p>\n\n<p><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%2F1vbqnsnb1l8zrnsp207z.png\" class=\"article-body-image-wrapper\"><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%2F1vbqnsnb1l8zrnsp207z.png\" alt=\"login\" width=\"800\" height=\"398\"><\/a><\/p>\n\n<blockquote>\n<p>For logging in our new user we will use use the POST 'api\/token' endpoint to generate our access and refresh tokens to allow authentication, we will can manually copy them as we are using postman to test and are yet to configure the endpoint with our react frontend<\/p>\n<\/blockquote>\n\n<p>3.<strong>Checking our UserProfile<\/strong><br>\nIn-order as to process an authenticated request using postman we have to paste in the access token we got when we logged in to the bearer token in authorization like so GET 'api\/profile':<\/p>\n\n<p><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%2F4uev8zediby4yw8axhgt.png\" class=\"article-body-image-wrapper\"><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%2F4uev8zediby4yw8axhgt.png\" alt=\"bearer\" width=\"800\" height=\"349\"><\/a><\/p>\n\n<p>thus getting the user profile that we created:<\/p>\n\n<p><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%2Fn1hk1wv8dzcej27qej44.png\" class=\"article-body-image-wrapper\"><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%2Fn1hk1wv8dzcej27qej44.png\" alt=\"User Profile\" width=\"800\" height=\"464\"><\/a><\/p>\n\n<p>4.<strong>Get your Notes<\/strong><br>\nA user can now access their notes when authenticated through the GET 'api\/notes' endpoint:<\/p>\n\n<p><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%2F9d01knrdnhmml6jev5rf.png\" class=\"article-body-image-wrapper\"><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%2F9d01knrdnhmml6jev5rf.png\" alt=\"notes\" width=\"800\" height=\"321\"><\/a><\/p>\n\n<blockquote>\n<p>Note that the list is empty as the user has not created a note yet<\/p>\n<\/blockquote>\n\n<h2>\n  \n  \n  Conclusion\n<\/h2>\n\n<p>In conclusion, I want to extend my heartfelt thanks to you for taking the time to read this article on JWT authentication in the Django backend of our React Django notes app. I hope that this article has been helpful and informative as we work towards creating a fully authenticated app. In the next part of this series, we will dive deeper into integrating authentication with the React frontend so that we can see the app in its full authenticated glory. If you're interested in exploring the code, you can find the link to the app on Github(<a href=\"https:\/\/github.com\/ki3ani\/my-notes-backend\" rel=\"noopener noreferrer\">ReactDjango Notes App<\/a>). Once again, thank you for reading and I look forward to sharing the next part of this series with you soon.<\/p>\n\n","category":["tutorial","django","api","jwt"]},{"title":"Building out a Notes App with React and a Django Rest API Part 2","pubDate":"Tue, 21 Mar 2023 15:01:16 +0000","link":"https:\/\/dev.to\/ki3ani\/building-my-notes-app-front-end-using-react-and-tailwind-part-2-4lkd","guid":"https:\/\/dev.to\/ki3ani\/building-my-notes-app-front-end-using-react-and-tailwind-part-2-4lkd","description":"<h2>\n  \n  \n  Introduction\n<\/h2>\n\n<p>Welcome back to Part 2 of the React Django article series! In Part 1, we created a Django REST API for our notes app. Now, we're going to dive into the frontend development using React and Tailwind. We'll be building a dynamic UI that can interact with our Django REST API. Throughout this journey, we'll learn about component-driven development, using React hooks, and building responsive UIs using Tailwind CSS. By the end of this part, we'll have a fully functional notes app with a sleek and responsive UI. So, let's dive in!<\/p>\n\n<h2>\n  \n  \n  Creating a React App:\n<\/h2>\n\n<p>Before we start building our notes app, we need to create a React app. This will provide us with a basic project structure and the necessary files to get started.<\/p>\n\n<p>To create a new React app, In your IDE open your terminal and navigate to the directory where you want to create the app. Then, run the following command:<\/p>\n\n<p><code>npx create-react-app &lt;appname&gt;<\/code><\/p>\n\n<p>We can then move in the React app folder then start the server confirming it is working:<\/p>\n\n<p><code>cd &lt;appname&gt;<\/code><br>\n<code>npm run start<\/code><\/p>\n\n<p><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%2Fitvpeuvyllndqo1jdz4b.png\" class=\"article-body-image-wrapper\"><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%2Fitvpeuvyllndqo1jdz4b.png\" alt=\"Reactstart\" width=\"800\" height=\"445\"><\/a><\/p>\n\n<blockquote>\n<p>React Startup<\/p>\n<\/blockquote>\n\n<p>Now that we have created our React app, let's install Tailwind CSS.<\/p>\n<h2>\n  \n  \n  Installing Tailwind CSS:\n<\/h2>\n\n<p>Tailwind CSS is a utility-first CSS framework that makes it easy to style your React components. To install Tailwind, we'll use npm, the package manager that comes with Node.js.<\/p>\n\n<p>In your terminal, run the following command to install Tailwind and its dependencies:<\/p>\n\n<p><code>npm install -D tailwindcss<\/code><br>\n<code>npx tailwindcss init<\/code><\/p>\n\n<blockquote>\n<p>Install tailwindcss via npm, and create your tailwind.config.js file.<\/p>\n<\/blockquote>\n\n<p>Add the paths to all of your template files in your tailwind.config.js file.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"cm\">\/** @type {import('tailwindcss').Config} *\/<\/span>\n<span class=\"nx\">module<\/span><span class=\"p\">.<\/span><span class=\"nx\">exports<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n  <span class=\"na\">content<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">.\/src\/**\/*.{html,js}<\/span><span class=\"dl\">\"<\/span><span class=\"p\">],<\/span>  \n  <span class=\"na\">theme<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n    <span class=\"na\">extend<\/span><span class=\"p\">:<\/span> <span class=\"p\">{},<\/span>\n  <span class=\"p\">},<\/span>\n  <span class=\"na\">plugins<\/span><span class=\"p\">:<\/span> <span class=\"p\">[],<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Add the <a class=\"mentioned-user\" href=\"https:\/\/dev.to\/tailwind\">@tailwind<\/a> directives for each of Tailwind\u2019s layers to your main CSS file.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"p\">@<\/span><span class=\"nd\">tailwind<\/span> <span class=\"nx\">base<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">@<\/span><span class=\"nd\">tailwind<\/span> <span class=\"nx\">components<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">@<\/span><span class=\"nd\">tailwind<\/span> <span class=\"nx\">utilities<\/span><span class=\"p\">;<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<blockquote>\n<p>This imports the base styles, components, and utility classes from Tailwind.<\/p>\n<\/blockquote>\n\n<p>That's it! We have now created our React app and installed Tailwind CSS. In the next part of this article, we'll start building the UI for our notes app using React and Tailwind.<\/p>\n\n<p>Apart from installing React and Tailwind, we also need to install Axios. Axios is a popular JavaScript library that is used to make HTTP requests from a web application. It is a promise-based library that provides an easy-to-use API for making asynchronous HTTP requests to REST endpoints and performing CRUD (Create, Read, Update, Delete) operations.<\/p>\n\n<p>Axios is commonly used in React applications to fetch data from APIs or backend servers, and update or delete data on the server-side. In our case, we will use Axios to make HTTP requests to our Django Rest API and perform CRUD operations on our data.<\/p>\n\n<p>To install Axios in your React project, you can use the following command in your terminal:<\/p>\n\n<p><code>npm install axios<\/code><\/p>\n\n<h1>\n  \n  \n  Creating Components\n<\/h1>\n\n<p>In our React app with Axios and Django REST API, we will be building multiple components that will work together to create a fully functional note-taking app. We will be building five components, including the NoteList, NoteForm, NoteDetail, Header, and Footer.<\/p>\n\n<p>Now, you might be wondering why we are using components in our app. Components are the building blocks of a React app, allowing us to split our user interface into small, reusable pieces of code that can be easily managed and updated.<\/p>\n\n<p>For example, we can create a component called NoteList, which will be responsible for displaying the list of notes created by the user. This component can be reused in different parts of our app, such as the home page, search page, and archive page. By creating a separate component for the NoteList, we can easily update or modify the way our notes are displayed without affecting the rest of the code.<\/p>\n\n<p>Similarly, we can create a component for the NoteForm, which will allow users to create new notes, and a component for displaying the details of each note, called NoteDetail. Additionally, we can create components for the header and footer of our app, which will include the app logo, navigation links, and copyright information.<\/p>\n\n<p>By breaking down our app into small, reusable components, we can easily modify or update a specific part of the app without affecting the rest of the code. This makes it easier to maintain and scale our app as it grows in complexity with Django REST API.<\/p>\n\n<p>Great, lets start off with the NoteList component to display all notes, In the src folder create a components folder and inside the components folder lets create a NoteList.js component.<\/p>\n\n<p><strong>1.<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"k\">import<\/span> <span class=\"nx\">React<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">useState<\/span><span class=\"p\">,<\/span> <span class=\"nx\">useEffect<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">react<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Link<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">react-router-dom<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">axios<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">axios<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">NoteForm<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">.\/NoteForm<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"kd\">function<\/span> <span class=\"nf\">NoteList<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n  <span class=\"c1\">\/\/ State variables for managing notes and note form visibility<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"p\">[<\/span><span class=\"nx\">notes<\/span><span class=\"p\">,<\/span> <span class=\"nx\">setNotes<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">useState<\/span><span class=\"p\">([]);<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"p\">[<\/span><span class=\"nx\">showNoteForm<\/span><span class=\"p\">,<\/span> <span class=\"nx\">setShowNoteForm<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">useState<\/span><span class=\"p\">(<\/span><span class=\"kc\">false<\/span><span class=\"p\">);<\/span>\n\n  <span class=\"c1\">\/\/ Fetches notes from the API when the component mounts<\/span>\n  <span class=\"nf\">useEffect<\/span><span class=\"p\">(()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">async<\/span> <span class=\"kd\">function<\/span> <span class=\"nf\">fetchNotes<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n      <span class=\"kd\">const<\/span> <span class=\"nx\">response<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nx\">axios<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">http:\/\/localhost:8000\/api\/notes\/<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n      <span class=\"nf\">setNotes<\/span><span class=\"p\">(<\/span><span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n    <span class=\"nf\">fetchNotes<\/span><span class=\"p\">();<\/span>\n  <span class=\"p\">},<\/span> <span class=\"p\">[]);<\/span>\n\n  <span class=\"c1\">\/\/ Deletes a note when the \"Delete\" button is clicked<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"nx\">handleDelete<\/span> <span class=\"o\">=<\/span> <span class=\"k\">async <\/span><span class=\"p\">(<\/span><span class=\"nx\">id<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">try<\/span> <span class=\"p\">{<\/span>\n      <span class=\"k\">await<\/span> <span class=\"nx\">axios<\/span><span class=\"p\">.<\/span><span class=\"k\">delete<\/span><span class=\"p\">(<\/span><span class=\"s2\">`http:\/\/localhost:8000\/api\/notes\/<\/span><span class=\"p\">${<\/span><span class=\"nx\">id<\/span><span class=\"p\">}<\/span><span class=\"s2\">\/`<\/span><span class=\"p\">);<\/span>\n      <span class=\"c1\">\/\/ Removes the deleted note from the state array<\/span>\n      <span class=\"nf\">setNotes<\/span><span class=\"p\">(<\/span><span class=\"nx\">notes<\/span><span class=\"p\">.<\/span><span class=\"nf\">filter<\/span><span class=\"p\">((<\/span><span class=\"nx\">note<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">note<\/span><span class=\"p\">.<\/span><span class=\"nx\">id<\/span> <span class=\"o\">!==<\/span> <span class=\"nx\">id<\/span><span class=\"p\">));<\/span>\n    <span class=\"p\">}<\/span> <span class=\"k\">catch <\/span><span class=\"p\">(<\/span><span class=\"nx\">error<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nf\">error<\/span><span class=\"p\">(<\/span><span class=\"nx\">error<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">};<\/span>\n\n  <span class=\"k\">return <\/span><span class=\"p\">(<\/span>\n    <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">container mx-auto px-4<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n      <span class=\"p\">{<\/span><span class=\"nx\">showNoteForm<\/span> <span class=\"p\">?<\/span> <span class=\"p\">(<\/span>\n        <span class=\"c1\">\/\/ Renders the note form component when showNoteForm is true<\/span>\n        <span class=\"o\">&lt;<\/span><span class=\"nx\">NoteForm<\/span> <span class=\"nx\">setNotes<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"nx\">setNotes<\/span><span class=\"p\">}<\/span> <span class=\"sr\">\/<\/span><span class=\"err\">&gt;\n<\/span>      <span class=\"p\">)<\/span> <span class=\"p\">:<\/span> <span class=\"p\">(<\/span>\n        <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span><span class=\"o\">&gt;<\/span>\n          <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">flex justify-between items-center my-8<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n            <span class=\"o\">&lt;<\/span><span class=\"nx\">button<\/span>\n              <span class=\"c1\">\/\/ Sets showNoteForm to true when the \"Create Note\" button is clicked<\/span>\n              <span class=\"nx\">onClick<\/span><span class=\"o\">=<\/span><span class=\"p\">{()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nf\">setShowNoteForm<\/span><span class=\"p\">(<\/span><span class=\"kc\">true<\/span><span class=\"p\">)}<\/span>\n              <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">bg-blue-500 text-white font-medium py-2 px-4 rounded hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2<\/span><span class=\"dl\">\"<\/span>\n            <span class=\"o\">&gt;<\/span>\n              <span class=\"nx\">Create<\/span> <span class=\"nx\">Note<\/span>\n            <span class=\"o\">&lt;<\/span><span class=\"sr\">\/button<\/span><span class=\"err\">&gt;\n<\/span>          <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>          <span class=\"p\">{<\/span><span class=\"nx\">notes<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">0<\/span> <span class=\"p\">?<\/span> <span class=\"p\">(<\/span>\n            <span class=\"c1\">\/\/ Renders a grid of note cards when there are notes to display<\/span>\n            <span class=\"o\">&lt;<\/span><span class=\"nx\">ul<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n              <span class=\"p\">{<\/span><span class=\"nx\">notes<\/span><span class=\"p\">.<\/span><span class=\"nf\">map<\/span><span class=\"p\">((<\/span><span class=\"nx\">note<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">(<\/span>\n                <span class=\"o\">&lt;<\/span><span class=\"nx\">li<\/span> <span class=\"nx\">key<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"nx\">note<\/span><span class=\"p\">.<\/span><span class=\"nx\">id<\/span><span class=\"p\">}<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">border border-gray-400 rounded-lg overflow-hidden shadow-md<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n                  <span class=\"o\">&lt;<\/span><span class=\"nx\">Link<\/span> <span class=\"nx\">to<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"s2\">`\/notes\/<\/span><span class=\"p\">${<\/span><span class=\"nx\">note<\/span><span class=\"p\">.<\/span><span class=\"nx\">id<\/span><span class=\"p\">}<\/span><span class=\"s2\">\/`<\/span><span class=\"p\">}<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">block<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n                    <span class=\"o\">&lt;<\/span><span class=\"nx\">img<\/span> <span class=\"nx\">src<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"nx\">note<\/span><span class=\"p\">.<\/span><span class=\"nx\">cover_image<\/span><span class=\"p\">}<\/span> <span class=\"nx\">alt<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"\"<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">w-full h-40 object-cover<\/span><span class=\"dl\">\"<\/span> <span class=\"o\">\/&gt;<\/span>\n                    <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">p-4<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n                      <span class=\"o\">&lt;<\/span><span class=\"nx\">h2<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">text-lg font-medium text-gray-900<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">{<\/span><span class=\"nx\">note<\/span><span class=\"p\">.<\/span><span class=\"nx\">title<\/span><span class=\"p\">}<\/span><span class=\"o\">&lt;<\/span><span class=\"sr\">\/h2<\/span><span class=\"err\">&gt;\n<\/span>                      <span class=\"o\">&lt;<\/span><span class=\"nx\">p<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">mt-2 text-gray-600<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">{<\/span><span class=\"nx\">note<\/span><span class=\"p\">.<\/span><span class=\"nx\">body<\/span><span class=\"p\">.<\/span><span class=\"nf\">slice<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">100<\/span><span class=\"p\">)}...<\/span><span class=\"o\">&lt;<\/span><span class=\"sr\">\/p<\/span><span class=\"err\">&gt;\n<\/span>                    <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>                  <span class=\"o\">&lt;<\/span><span class=\"sr\">\/Link<\/span><span class=\"err\">&gt;\n<\/span>                  <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">bg-gray-100 px-4 py-3<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n                    <span class=\"o\">&lt;<\/span><span class=\"nx\">button<\/span>\n                      <span class=\"c1\">\/\/ Deletes the note when the \"Delete\" button is clicked<\/span>\n                      <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">text-red-500 font-medium hover:text-red-600<\/span><span class=\"dl\">\"<\/span>\n                      <span class=\"nx\">onClick<\/span><span class=\"o\">=<\/span><span class=\"p\">{()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nf\">handleDelete<\/span><span class=\"p\">(<\/span><span class=\"nx\">note<\/span><span class=\"p\">.<\/span><span class=\"nx\">id<\/span><span class=\"p\">)}<\/span>\n                    <span class=\"o\">&gt;<\/span>\n                      <span class=\"nx\">Delete<\/span>\n                    <span class=\"o\">&lt;<\/span><span class=\"sr\">\/button<\/span><span class=\"err\">&gt;\n<\/span>                  <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>                <span class=\"o\">&lt;<\/span><span class=\"sr\">\/li<\/span><span class=\"err\">&gt;\n<\/span>              <span class=\"p\">))}<\/span>\n            <span class=\"o\">&lt;<\/span><span class=\"sr\">\/ul<\/span><span class=\"err\">&gt;\n<\/span>          <span class=\"p\">)<\/span> <span class=\"p\">:<\/span> <span class=\"p\">(<\/span>\n            <span class=\"c1\">\/\/ Renders a message when there are no notes to display<\/span>\n            <span class=\"o\">&lt;<\/span><span class=\"nx\">p<\/span><span class=\"o\">&gt;<\/span><span class=\"nx\">No<\/span> <span class=\"nx\">notes<\/span> <span class=\"nx\">found<\/span><span class=\"p\">.<\/span><span class=\"o\">&lt;<\/span><span class=\"sr\">\/p<\/span><span class=\"err\">&gt;\n<\/span>          <span class=\"p\">)}<\/span>\n        <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>      <span class=\"p\">)}<\/span>\n    <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>  <span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"k\">default<\/span> <span class=\"nx\">NoteList<\/span><span class=\"p\">;<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>This code defines a NoteList component in React that fetches a list of notes from an API, renders them as a list, and provides an option to delete each note.<\/p>\n\n<p>The component uses useState and useEffect hooks to manage the state of the component. useState is used to manage the state of the notes array and to toggle the visibility of the NoteForm component, which is rendered when the \"Create Note\" button is clicked. useEffect is used to fetch the list of notes from the API when the component is mounted.<\/p>\n\n<p>The handleDelete function is defined to delete a note from the list of notes and the API when the \"Delete\" button is clicked. This function uses the axios library to send a DELETE request to the API and then removes the note from the local notes array using the setNotes function.<\/p>\n\n<p>The NoteList component renders either the NoteForm component or the list of notes depending on whether the showNoteForm state is true or false, respectively. If the list of notes is rendered, each note is rendered as a li element with a link to the note details page and a \"Delete\" button. If there are no notes in the notes array, a message is displayed indicating that no notes were found.<\/p>\n\n<p><strong>2.Next we have our Note Detail component:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"k\">import<\/span> <span class=\"nx\">React<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">useState<\/span><span class=\"p\">,<\/span> <span class=\"nx\">useEffect<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">useParams<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react-router-dom<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">axios<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">axios<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">NoteForm<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/NoteForm<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">moment<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">moment<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span> <span class=\"c1\">\/\/ import moment here<\/span>\n\n<span class=\"kd\">function<\/span> <span class=\"nf\">NoteDetail<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">id<\/span> <span class=\"p\">}<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">useParams<\/span><span class=\"p\">();<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"p\">[<\/span><span class=\"nx\">note<\/span><span class=\"p\">,<\/span> <span class=\"nx\">setNote<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">useState<\/span><span class=\"p\">(<\/span><span class=\"kc\">null<\/span><span class=\"p\">);<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"p\">[<\/span><span class=\"nx\">editing<\/span><span class=\"p\">,<\/span> <span class=\"nx\">setEditing<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">useState<\/span><span class=\"p\">(<\/span><span class=\"kc\">false<\/span><span class=\"p\">);<\/span>\n\n  <span class=\"c1\">\/\/ Fetch the note with the given id from the API when the component mounts<\/span>\n  <span class=\"nf\">useEffect<\/span><span class=\"p\">(()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">axios<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"s2\">`http:\/\/localhost:8000\/api\/notes\/<\/span><span class=\"p\">${<\/span><span class=\"nx\">id<\/span><span class=\"p\">}<\/span><span class=\"s2\">\/`<\/span><span class=\"p\">).<\/span><span class=\"nf\">then<\/span><span class=\"p\">((<\/span><span class=\"nx\">response<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nf\">setNote<\/span><span class=\"p\">(<\/span><span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">});<\/span>\n  <span class=\"p\">},<\/span> <span class=\"p\">[<\/span><span class=\"nx\">id<\/span><span class=\"p\">]);<\/span>\n\n  <span class=\"c1\">\/\/ Update the note in the API and local state when the form is submitted<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"nx\">handleUpdate<\/span> <span class=\"o\">=<\/span> <span class=\"k\">async <\/span><span class=\"p\">(<\/span><span class=\"nx\">formData<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">try<\/span> <span class=\"p\">{<\/span>\n      <span class=\"kd\">const<\/span> <span class=\"nx\">response<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nx\">axios<\/span><span class=\"p\">.<\/span><span class=\"nf\">patch<\/span><span class=\"p\">(<\/span>\n        <span class=\"s2\">`http:\/\/localhost:8000\/api\/notes\/<\/span><span class=\"p\">${<\/span><span class=\"nx\">id<\/span><span class=\"p\">}<\/span><span class=\"s2\">\/`<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">formData<\/span>\n      <span class=\"p\">);<\/span>\n      <span class=\"nf\">setNote<\/span><span class=\"p\">(<\/span><span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">);<\/span>\n      <span class=\"nf\">setEditing<\/span><span class=\"p\">(<\/span><span class=\"kc\">false<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span> <span class=\"k\">catch <\/span><span class=\"p\">(<\/span><span class=\"nx\">error<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nf\">error<\/span><span class=\"p\">(<\/span><span class=\"nx\">error<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">};<\/span>\n\n  <span class=\"c1\">\/\/ If the user is editing the note, show the NoteForm component<\/span>\n  <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"nx\">editing<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"o\">&lt;<\/span><span class=\"nx\">NoteForm<\/span> <span class=\"nx\">note<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"nx\">note<\/span><span class=\"p\">}<\/span> <span class=\"nx\">handleSubmit<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"nx\">handleUpdate<\/span><span class=\"p\">}<\/span> <span class=\"sr\">\/&gt;<\/span><span class=\"err\">;\n<\/span>  <span class=\"p\">}<\/span>\n\n  <span class=\"c1\">\/\/ If the note hasn't been fetched yet, show a loading message<\/span>\n  <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"nx\">note<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span><span class=\"o\">&gt;<\/span><span class=\"nx\">Loading<\/span><span class=\"p\">...<\/span><span class=\"o\">&lt;<\/span><span class=\"sr\">\/div&gt;<\/span><span class=\"err\">;\n<\/span>  <span class=\"p\">}<\/span>\n\n  <span class=\"c1\">\/\/ Otherwise, render the note details<\/span>\n  <span class=\"k\">return <\/span><span class=\"p\">(<\/span>\n    <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">max-w-lg mx-auto my-8<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n      <span class=\"o\">&lt;<\/span><span class=\"nx\">img<\/span>\n        <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">h-64 w-full object-cover mb-4<\/span><span class=\"dl\">\"<\/span>\n        <span class=\"nx\">src<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"nx\">note<\/span><span class=\"p\">.<\/span><span class=\"nx\">cover_image<\/span><span class=\"p\">}<\/span>\n        <span class=\"nx\">alt<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"nx\">note<\/span><span class=\"p\">.<\/span><span class=\"nx\">title<\/span><span class=\"p\">}<\/span>\n      <span class=\"sr\">\/<\/span><span class=\"err\">&gt;\n<\/span>      <span class=\"o\">&lt;<\/span><span class=\"nx\">h1<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">text-2xl font-bold text-gray-800 mb-4<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">{<\/span><span class=\"nx\">note<\/span><span class=\"p\">.<\/span><span class=\"nx\">title<\/span><span class=\"p\">}<\/span><span class=\"o\">&lt;<\/span><span class=\"sr\">\/h1<\/span><span class=\"err\">&gt;\n<\/span>      <span class=\"o\">&lt;<\/span><span class=\"nx\">p<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">text-gray-600 text-base mb-4<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">{<\/span><span class=\"nx\">note<\/span><span class=\"p\">.<\/span><span class=\"nx\">body<\/span><span class=\"p\">}<\/span><span class=\"o\">&lt;<\/span><span class=\"sr\">\/p<\/span><span class=\"err\">&gt;\n<\/span>      <span class=\"o\">&lt;<\/span><span class=\"nx\">p<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">text-gray-500 text-sm<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n        <span class=\"nx\">Last<\/span> <span class=\"nx\">updated<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span><span class=\"nf\">moment<\/span><span class=\"p\">(<\/span><span class=\"nx\">note<\/span><span class=\"p\">.<\/span><span class=\"nx\">updated<\/span><span class=\"p\">).<\/span><span class=\"nf\">format<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">MMMM Do YYYY, h:mm:ss a<\/span><span class=\"dl\">\"<\/span><span class=\"p\">)}<\/span>\n      <span class=\"o\">&lt;<\/span><span class=\"sr\">\/p<\/span><span class=\"err\">&gt;\n<\/span>      <span class=\"o\">&lt;<\/span><span class=\"nx\">button<\/span>\n        <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mt-4<\/span><span class=\"dl\">\"<\/span>\n        <span class=\"nx\">onClick<\/span><span class=\"o\">=<\/span><span class=\"p\">{()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nf\">setEditing<\/span><span class=\"p\">(<\/span><span class=\"kc\">true<\/span><span class=\"p\">)}<\/span>\n      <span class=\"o\">&gt;<\/span>\n        <span class=\"nx\">Edit<\/span> <span class=\"nx\">Note<\/span>\n      <span class=\"o\">&lt;<\/span><span class=\"sr\">\/button<\/span><span class=\"err\">&gt;\n<\/span>    <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>  <span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"k\">default<\/span> <span class=\"nx\">NoteDetail<\/span><span class=\"p\">;<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>In summary, this component fetches a single note from the API based on the ID in the URL, and displays its details along with an \"Edit\" button. If the \"Edit\" button is clicked, the component switches to editing mode and shows the NoteForm component. When the form is submitted, the note is updated in the API and local state, and the component switches back to display mode. The moment library is used to format the \"Last updated\" timestamp.<\/p>\n\n<p><strong>3.Next we can now make our NoteForm to handle creating and editing notes:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"k\">import<\/span> <span class=\"nx\">React<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">useState<\/span><span class=\"p\">,<\/span> <span class=\"nx\">useEffect<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">react<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">useNavigate<\/span><span class=\"p\">,<\/span> <span class=\"nx\">useParams<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">react-router-dom<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">axios<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">axios<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"kd\">function<\/span> <span class=\"nf\">NoteForm<\/span><span class=\"p\">({<\/span> <span class=\"nx\">setNotes<\/span> <span class=\"o\">=<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{}<\/span> <span class=\"p\">})<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"nx\">navigate<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">useNavigate<\/span><span class=\"p\">();<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">id<\/span> <span class=\"p\">}<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">useParams<\/span><span class=\"p\">();<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"p\">[<\/span><span class=\"nx\">title<\/span><span class=\"p\">,<\/span> <span class=\"nx\">setTitle<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">useState<\/span><span class=\"p\">(<\/span><span class=\"dl\">''<\/span><span class=\"p\">);<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"p\">[<\/span><span class=\"nx\">coverImage<\/span><span class=\"p\">,<\/span> <span class=\"nx\">setCoverImage<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">useState<\/span><span class=\"p\">(<\/span><span class=\"kc\">null<\/span><span class=\"p\">);<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"p\">[<\/span><span class=\"nx\">body<\/span><span class=\"p\">,<\/span> <span class=\"nx\">setBody<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">useState<\/span><span class=\"p\">(<\/span><span class=\"dl\">''<\/span><span class=\"p\">);<\/span>\n\n  <span class=\"nf\">useEffect<\/span><span class=\"p\">(()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"nx\">id<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">axios<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"s2\">`http:\/\/localhost:8000\/api\/notes\/<\/span><span class=\"p\">${<\/span><span class=\"nx\">id<\/span><span class=\"p\">}<\/span><span class=\"s2\">\/`<\/span><span class=\"p\">).<\/span><span class=\"nf\">then<\/span><span class=\"p\">((<\/span><span class=\"nx\">response<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nf\">setTitle<\/span><span class=\"p\">(<\/span><span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">.<\/span><span class=\"nx\">title<\/span><span class=\"p\">);<\/span>\n        <span class=\"nf\">setBody<\/span><span class=\"p\">(<\/span><span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">.<\/span><span class=\"nx\">body<\/span><span class=\"p\">);<\/span>\n      <span class=\"p\">});<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">},<\/span> <span class=\"p\">[<\/span><span class=\"nx\">id<\/span><span class=\"p\">]);<\/span>\n\n  <span class=\"kd\">const<\/span> <span class=\"nx\">handleSubmit<\/span> <span class=\"o\">=<\/span> <span class=\"k\">async <\/span><span class=\"p\">(<\/span><span class=\"nx\">e<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">e<\/span><span class=\"p\">.<\/span><span class=\"nf\">preventDefault<\/span><span class=\"p\">();<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">formData<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nc\">FormData<\/span><span class=\"p\">();<\/span>\n    <span class=\"nx\">formData<\/span><span class=\"p\">.<\/span><span class=\"nf\">append<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">title<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">title<\/span><span class=\"p\">);<\/span>\n    <span class=\"nx\">formData<\/span><span class=\"p\">.<\/span><span class=\"nf\">append<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">body<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">body<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"nx\">coverImage<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">formData<\/span><span class=\"p\">.<\/span><span class=\"nf\">append<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">cover_image<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">coverImage<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n    <span class=\"k\">try<\/span> <span class=\"p\">{<\/span>\n      <span class=\"kd\">let<\/span> <span class=\"nx\">response<\/span><span class=\"p\">;<\/span>\n      <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"nx\">id<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">response<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nx\">axios<\/span><span class=\"p\">.<\/span><span class=\"nf\">patch<\/span><span class=\"p\">(<\/span><span class=\"s2\">`http:\/\/localhost:8000\/api\/notes\/<\/span><span class=\"p\">${<\/span><span class=\"nx\">id<\/span><span class=\"p\">}<\/span><span class=\"s2\">\/`<\/span><span class=\"p\">,<\/span> <span class=\"nx\">formData<\/span><span class=\"p\">);<\/span>\n        <span class=\"nf\">setNotes<\/span><span class=\"p\">((<\/span><span class=\"nx\">prevNotes<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span>\n          <span class=\"nx\">prevNotes<\/span><span class=\"p\">.<\/span><span class=\"nf\">map<\/span><span class=\"p\">((<\/span><span class=\"nx\">note<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">(<\/span><span class=\"nx\">note<\/span><span class=\"p\">.<\/span><span class=\"nx\">id<\/span> <span class=\"o\">===<\/span> <span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">.<\/span><span class=\"nx\">id<\/span> <span class=\"p\">?<\/span> <span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span> <span class=\"p\">:<\/span> <span class=\"nx\">note<\/span><span class=\"p\">))<\/span>\n        <span class=\"p\">);<\/span>\n        <span class=\"nf\">alert<\/span><span class=\"p\">(<\/span><span class=\"s2\">`Note updated successfully!`<\/span><span class=\"p\">,<\/span> <span class=\"nf\">navigate<\/span><span class=\"p\">(<\/span><span class=\"s2\">`\/notes\/<\/span><span class=\"p\">${<\/span><span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">.<\/span><span class=\"nx\">id<\/span><span class=\"p\">}<\/span><span class=\"s2\">`<\/span><span class=\"p\">));<\/span>\n\n      <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">response<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nx\">axios<\/span><span class=\"p\">.<\/span><span class=\"nf\">post<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">http:\/\/localhost:8000\/api\/notes\/<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">formData<\/span><span class=\"p\">);<\/span>\n        <span class=\"nf\">setNotes<\/span><span class=\"p\">((<\/span><span class=\"nx\">prevNotes<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">[<\/span><span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">,<\/span> <span class=\"p\">...<\/span><span class=\"nx\">prevNotes<\/span><span class=\"p\">]);<\/span>\n        <span class=\"nf\">alert<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">Note created successfully!<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nf\">navigate<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">\/<\/span><span class=\"dl\">'<\/span><span class=\"p\">));<\/span>\n      <span class=\"p\">}<\/span>\n      <span class=\"nf\">setTitle<\/span><span class=\"p\">(<\/span><span class=\"dl\">''<\/span><span class=\"p\">);<\/span>\n      <span class=\"nf\">setBody<\/span><span class=\"p\">(<\/span><span class=\"dl\">''<\/span><span class=\"p\">);<\/span>\n      <span class=\"nf\">setCoverImage<\/span><span class=\"p\">(<\/span><span class=\"kc\">null<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span> <span class=\"k\">catch <\/span><span class=\"p\">(<\/span><span class=\"nx\">error<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nf\">error<\/span><span class=\"p\">(<\/span><span class=\"nx\">error<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">};<\/span>\n\n\n  <span class=\"k\">return <\/span><span class=\"p\">(<\/span>\n    <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">container mx-auto px-4<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n      <span class=\"o\">&lt;<\/span><span class=\"nx\">form<\/span> <span class=\"nx\">onSubmit<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"nx\">handleSubmit<\/span><span class=\"p\">}<\/span><span class=\"o\">&gt;<\/span>\n        <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">mb-4<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n          <span class=\"o\">&lt;<\/span><span class=\"nx\">label<\/span> <span class=\"nx\">htmlFor<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">title<\/span><span class=\"dl\">\"<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">block font-medium text-gray-700<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n            <span class=\"nx\">Title<\/span>\n          <span class=\"o\">&lt;<\/span><span class=\"sr\">\/label<\/span><span class=\"err\">&gt;\n<\/span>          <span class=\"o\">&lt;<\/span><span class=\"nx\">input<\/span>\n            <span class=\"nx\">type<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">text<\/span><span class=\"dl\">\"<\/span>\n            <span class=\"nx\">name<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">title<\/span><span class=\"dl\">\"<\/span>\n            <span class=\"nx\">id<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">title<\/span><span class=\"dl\">\"<\/span>\n            <span class=\"nx\">value<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"nx\">title<\/span><span class=\"p\">}<\/span>\n            <span class=\"nx\">onChange<\/span><span class=\"o\">=<\/span><span class=\"p\">{(<\/span><span class=\"nx\">e<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nf\">setTitle<\/span><span class=\"p\">(<\/span><span class=\"nx\">e<\/span><span class=\"p\">.<\/span><span class=\"nx\">target<\/span><span class=\"p\">.<\/span><span class=\"nx\">value<\/span><span class=\"p\">)}<\/span>\n            <span class=\"nx\">required<\/span>\n            <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">border border-gray-400 rounded w-full px-3 py-2 mt-1 text-gray-900<\/span><span class=\"dl\">\"<\/span>\n          <span class=\"o\">\/&gt;<\/span>\n        <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>        <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">mb-4<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n          <span class=\"o\">&lt;<\/span><span class=\"nx\">label<\/span> <span class=\"nx\">htmlFor<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">cover_image<\/span><span class=\"dl\">\"<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">block font-medium text-gray-700<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n            <span class=\"nx\">Cover<\/span> <span class=\"nx\">Image<\/span>\n          <span class=\"o\">&lt;<\/span><span class=\"sr\">\/label<\/span><span class=\"err\">&gt;\n<\/span>          <span class=\"o\">&lt;<\/span><span class=\"nx\">input<\/span>\n            <span class=\"nx\">type<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">file<\/span><span class=\"dl\">\"<\/span>\n            <span class=\"nx\">name<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">cover_image<\/span><span class=\"dl\">\"<\/span>\n            <span class=\"nx\">id<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">cover_image<\/span><span class=\"dl\">\"<\/span>\n            <span class=\"nx\">onChange<\/span><span class=\"o\">=<\/span><span class=\"p\">{(<\/span><span class=\"nx\">e<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nf\">setCoverImage<\/span><span class=\"p\">(<\/span><span class=\"nx\">e<\/span><span class=\"p\">.<\/span><span class=\"nx\">target<\/span><span class=\"p\">.<\/span><span class=\"nx\">files<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">])}<\/span>\n            <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">border border-gray-400 rounded w-full px-3 py-2 mt-1 text-gray-900<\/span><span class=\"dl\">\"<\/span>\n          <span class=\"o\">\/&gt;<\/span>\n        <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>        <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">mb-4<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n          <span class=\"o\">&lt;<\/span><span class=\"nx\">label<\/span> <span class=\"nx\">htmlFor<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">body<\/span><span class=\"dl\">\"<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">block font-medium text-gray-700<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n            <span class=\"nx\">Body<\/span>\n          <span class=\"o\">&lt;<\/span><span class=\"sr\">\/label<\/span><span class=\"err\">&gt;\n<\/span>          <span class=\"o\">&lt;<\/span><span class=\"nx\">textarea<\/span>\n            <span class=\"nx\">name<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">body<\/span><span class=\"dl\">\"<\/span>\n            <span class=\"nx\">id<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">body<\/span><span class=\"dl\">\"<\/span>\n            <span class=\"nx\">value<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"nx\">body<\/span><span class=\"p\">}<\/span>\n            <span class=\"nx\">onChange<\/span><span class=\"o\">=<\/span><span class=\"p\">{(<\/span><span class=\"nx\">e<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nf\">setBody<\/span><span class=\"p\">(<\/span><span class=\"nx\">e<\/span><span class=\"p\">.<\/span><span class=\"nx\">target<\/span><span class=\"p\">.<\/span><span class=\"nx\">value<\/span><span class=\"p\">)}<\/span>\n            <span class=\"nx\">required<\/span>\n            <span class=\"nx\">rows<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">5<\/span><span class=\"dl\">\"<\/span>\n            <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">border border-gray-400 rounded w-full px-3 py-2 mt-1 text-gray-900<\/span><span class=\"dl\">\"<\/span>\n          <span class=\"o\">&gt;&lt;<\/span><span class=\"sr\">\/textarea<\/span><span class=\"err\">&gt;\n<\/span>        <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>        <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">mt-6<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n          <span class=\"o\">&lt;<\/span><span class=\"nx\">button<\/span>\n            <span class=\"nx\">type<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">submit<\/span><span class=\"dl\">\"<\/span>\n            <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">bg-blue-500 text-white font-medium py-2 px-4 rounded hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2<\/span><span class=\"dl\">\"<\/span>\n          <span class=\"o\">&gt;<\/span>\n            <span class=\"p\">{<\/span><span class=\"nx\">id<\/span> <span class=\"p\">?<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Update Note<\/span><span class=\"dl\">'<\/span> <span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Create Note<\/span><span class=\"dl\">'<\/span><span class=\"p\">}<\/span>\n          <span class=\"o\">&lt;<\/span><span class=\"sr\">\/button<\/span><span class=\"err\">&gt;\n<\/span>        <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>      <span class=\"o\">&lt;<\/span><span class=\"sr\">\/form<\/span><span class=\"err\">&gt;\n<\/span>    <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>  <span class=\"p\">);<\/span>\n\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"k\">default<\/span> <span class=\"nx\">NoteForm<\/span><span class=\"p\">;<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>This is a React functional component called NoteForm that creates a form for creating or updating notes. It uses hooks such as useState, useEffect and useParams to manage state and navigate between pages. It also uses the axios library to make HTTP requests to a backend server.<\/p>\n\n<p>The component takes in a prop called setNotes which is a function that updates the list of notes. It initializes the navigate and id variables using the useNavigate and useParams hooks respectively. title, coverImage and body are states initialized using the useState hook.<\/p>\n\n<p>The useEffect hook is used to fetch the details of an existing note using the id parameter passed in the URL. When the id changes, the useEffect hook is triggered and the note details are fetched using a GET request to the backend server.<\/p>\n\n<p>The handleSubmit function is called when the form is submitted. It first creates a FormData object and appends the title, body, and coverImage fields to it. It then makes an HTTP request to the backend server to either update an existing note using a PATCH request or create a new note using a POST request. The setNotes function is called to update the list of notes with the updated or new note. Finally, the input fields are reset.<\/p>\n\n<p>The return statement returns the JSX code for the form with input fields for the title, coverImage, and body. The button element is used to submit the form with either an 'Update Note' or 'Create Note' label depending on whether an id is present or not.<\/p>\n\n<p><strong>4.Next we create the Header.js component which will handle navigation and hold our light\/dark mode functionality:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Link<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react-router-dom<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">useState<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"kd\">function<\/span> <span class=\"nf\">Header<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"p\">[<\/span><span class=\"nx\">isDarkMode<\/span><span class=\"p\">,<\/span> <span class=\"nx\">setIsDarkMode<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">useState<\/span><span class=\"p\">(<\/span><span class=\"kc\">false<\/span><span class=\"p\">);<\/span>\n\n  <span class=\"kd\">const<\/span> <span class=\"nx\">handleDarkModeToggle<\/span> <span class=\"o\">=<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nf\">setIsDarkMode<\/span><span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"nx\">isDarkMode<\/span><span class=\"p\">);<\/span>\n    <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nx\">body<\/span><span class=\"p\">.<\/span><span class=\"nx\">classList<\/span><span class=\"p\">.<\/span><span class=\"nf\">toggle<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">bg-gray-800<\/span><span class=\"dl\">\"<\/span><span class=\"p\">);<\/span>\n    <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nx\">body<\/span><span class=\"p\">.<\/span><span class=\"nx\">classList<\/span><span class=\"p\">.<\/span><span class=\"nf\">toggle<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">text-white<\/span><span class=\"dl\">\"<\/span><span class=\"p\">);<\/span>\n  <span class=\"p\">};<\/span>\n\n  <span class=\"k\">return <\/span><span class=\"p\">(<\/span>\n    <span class=\"o\">&lt;<\/span><span class=\"nx\">header<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">flex justify-between items-center px-4 py-6<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n      <span class=\"o\">&lt;<\/span><span class=\"nx\">Link<\/span> <span class=\"nx\">to<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">\/<\/span><span class=\"dl\">\"<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">text-2xl font-bold<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n        <span class=\"nx\">Notes<\/span>\n      <span class=\"o\">&lt;<\/span><span class=\"sr\">\/Link<\/span><span class=\"err\">&gt;\n<\/span>      <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">flex items-center<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n        <span class=\"o\">&lt;<\/span><span class=\"nx\">button<\/span>\n          <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">p-1 text-gray-700 dark:text-gray-300<\/span><span class=\"dl\">\"<\/span>\n          <span class=\"nx\">onClick<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"nx\">handleDarkModeToggle<\/span><span class=\"p\">}<\/span>\n        <span class=\"o\">&gt;<\/span>\n          <span class=\"p\">{<\/span><span class=\"nx\">isDarkMode<\/span> <span class=\"p\">?<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">\u2600\ufe0f<\/span><span class=\"dl\">\"<\/span> <span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">\ud83c\udf19<\/span><span class=\"dl\">\"<\/span><span class=\"p\">}<\/span>\n        <span class=\"o\">&lt;<\/span><span class=\"sr\">\/button<\/span><span class=\"err\">&gt;\n<\/span>        <span class=\"o\">&lt;<\/span><span class=\"nx\">a<\/span>\n          <span class=\"nx\">href<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">https:\/\/github.com\/your-github-link<\/span><span class=\"dl\">\"<\/span>\n          <span class=\"nx\">target<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">_blank<\/span><span class=\"dl\">\"<\/span>\n          <span class=\"nx\">rel<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">noreferrer<\/span><span class=\"dl\">\"<\/span>\n          <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">ml-4 text-gray-700 dark:text-gray-300<\/span><span class=\"dl\">\"<\/span>\n        <span class=\"o\">&gt;<\/span>\n        <span class=\"o\">&lt;<\/span><span class=\"sr\">\/a<\/span><span class=\"err\">&gt;\n<\/span>      <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>    <span class=\"o\">&lt;<\/span><span class=\"sr\">\/header<\/span><span class=\"err\">&gt;\n<\/span>  <span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"k\">default<\/span> <span class=\"nx\">Header<\/span><span class=\"p\">;<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>This is a functional component named Header that is used to render the header section of the application. It imports two hooks, Link and useState, from the react-router-dom and react libraries, respectively.<\/p>\n\n<p>Inside the Header component, there is a state variable isDarkMode that is initially set to false using the useState hook. The handleDarkModeToggle function is used to toggle the value of isDarkMode between true and false and to toggle the classes of the body element to change the background color and text color of the application.<\/p>\n\n<p>The return statement of the component contains an HTML header element with two child elements. The first child element is a Link component that links to the home page of the application. The second child element is a div element that contains a button and a link to a GitHub repository. The button's text changes depending on whether the application is in dark mode or not.<\/p>\n\n<blockquote>\n<p>we wil need to add a style.css in our src folder file to handle our dark-light mode feature<br>\n<\/p>\n<\/blockquote>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight css\"><code><span class=\"nd\">:root<\/span> <span class=\"p\">{<\/span>\n    <span class=\"py\">--primary-color<\/span><span class=\"p\">:<\/span> <span class=\"m\">#3b82f6<\/span><span class=\"p\">;<\/span>\n    <span class=\"py\">--secondary-color<\/span><span class=\"p\">:<\/span> <span class=\"m\">#6b7280<\/span><span class=\"p\">;<\/span>\n    <span class=\"py\">--background-color<\/span><span class=\"p\">:<\/span> <span class=\"m\">#f9fafb<\/span><span class=\"p\">;<\/span>\n    <span class=\"py\">--text-color<\/span><span class=\"p\">:<\/span> <span class=\"m\">#111827<\/span><span class=\"p\">;<\/span>\n  <span class=\"p\">}<\/span>\n\n  <span class=\"nc\">.dark-mode<\/span> <span class=\"p\">{<\/span>\n    <span class=\"py\">--primary-color<\/span><span class=\"p\">:<\/span> <span class=\"m\">#93c5fd<\/span><span class=\"p\">;<\/span>\n    <span class=\"py\">--secondary-color<\/span><span class=\"p\">:<\/span> <span class=\"m\">#cbd5e1<\/span><span class=\"p\">;<\/span>\n    <span class=\"py\">--background-color<\/span><span class=\"p\">:<\/span> <span class=\"m\">#1f2937<\/span><span class=\"p\">;<\/span>\n    <span class=\"py\">--text-color<\/span><span class=\"p\">:<\/span> <span class=\"m\">#f9fafb<\/span><span class=\"p\">;<\/span>\n  <span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>5.Next, we can do the Footer.js:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"c1\">\/\/ This component represents the website's footer, which displays the creator's name and a link to their GitHub profile<\/span>\n<span class=\"kd\">function<\/span> <span class=\"nf\">Footer<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">return <\/span><span class=\"p\">(<\/span>\n    <span class=\"o\">&lt;<\/span><span class=\"nx\">footer<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">bg-blue-100 py-4 mt-12<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n      <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">container mx-auto text-center text-sm text-gray-500<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n        <span class=\"nx\">Made<\/span> <span class=\"kd\">with<\/span> <span class=\"err\">\u2764\ufe0f<\/span> <span class=\"nx\">by<\/span> <span class=\"o\">&lt;<\/span><span class=\"nx\">a<\/span> <span class=\"nx\">href<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">https:\/\/github.com\/ki3ani<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span><span class=\"nx\">ki3ani<\/span><span class=\"o\">&lt;<\/span><span class=\"sr\">\/a<\/span><span class=\"err\">&gt;\n<\/span>      <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>    <span class=\"o\">&lt;<\/span><span class=\"sr\">\/footer<\/span><span class=\"err\">&gt;\n<\/span>  <span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"k\">default<\/span> <span class=\"nx\">Footer<\/span><span class=\"p\">;<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>6.And finally we have the App.js:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">BrowserRouter<\/span> <span class=\"k\">as<\/span> <span class=\"nx\">Router<\/span><span class=\"p\">,<\/span> <span class=\"nx\">Routes<\/span><span class=\"p\">,<\/span> <span class=\"nx\">Route<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react-router-dom<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">Header<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/components\/Header<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">Footer<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/components\/Footer<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">NoteList<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/components\/NoteList<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">NoteDetail<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/components\/NoteDetail<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">NoteForm<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/components\/NoteForm<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"kd\">function<\/span> <span class=\"nf\">App<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">return <\/span><span class=\"p\">(<\/span>\n    <span class=\"o\">&lt;<\/span><span class=\"nx\">Router<\/span><span class=\"o\">&gt;<\/span>\n      <span class=\"o\">&lt;<\/span><span class=\"nx\">div<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">flex flex-col h-screen<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n        <span class=\"o\">&lt;<\/span><span class=\"nx\">Header<\/span> <span class=\"o\">\/&gt;<\/span>\n        <span class=\"o\">&lt;<\/span><span class=\"nx\">main<\/span> <span class=\"nx\">className<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">flex-1 overflow-y-auto<\/span><span class=\"dl\">\"<\/span><span class=\"o\">&gt;<\/span>\n          <span class=\"o\">&lt;<\/span><span class=\"nx\">Routes<\/span><span class=\"o\">&gt;<\/span>\n            <span class=\"o\">&lt;<\/span><span class=\"nx\">Route<\/span> <span class=\"nx\">path<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">\/<\/span><span class=\"dl\">\"<\/span> <span class=\"nx\">element<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">NoteList<\/span> <span class=\"o\">\/&gt;<\/span><span class=\"p\">}<\/span> <span class=\"sr\">\/<\/span><span class=\"err\">&gt;\n<\/span>            <span class=\"o\">&lt;<\/span><span class=\"nx\">Route<\/span> <span class=\"nx\">path<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">\/notes\/:id<\/span><span class=\"dl\">\"<\/span> <span class=\"nx\">element<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">NoteDetail<\/span> <span class=\"o\">\/&gt;<\/span><span class=\"p\">}<\/span> <span class=\"sr\">\/<\/span><span class=\"err\">&gt;\n<\/span>            <span class=\"o\">&lt;<\/span><span class=\"nx\">Route<\/span> <span class=\"nx\">path<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">\/create<\/span><span class=\"dl\">\"<\/span> <span class=\"nx\">element<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">NoteForm<\/span> <span class=\"o\">\/&gt;<\/span><span class=\"p\">}<\/span> <span class=\"sr\">\/<\/span><span class=\"err\">&gt;\n<\/span>            <span class=\"o\">&lt;<\/span><span class=\"nx\">Route<\/span> <span class=\"nx\">path<\/span><span class=\"o\">=<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">\/edit\/:id<\/span><span class=\"dl\">\"<\/span> <span class=\"nx\">element<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">NoteForm<\/span> <span class=\"o\">\/&gt;<\/span><span class=\"p\">}<\/span> <span class=\"sr\">\/<\/span><span class=\"err\">&gt;\n<\/span>          <span class=\"o\">&lt;<\/span><span class=\"sr\">\/Routes<\/span><span class=\"err\">&gt;\n<\/span>        <span class=\"o\">&lt;<\/span><span class=\"sr\">\/main<\/span><span class=\"err\">&gt;\n<\/span>        <span class=\"o\">&lt;<\/span><span class=\"nx\">Footer<\/span> <span class=\"o\">\/&gt;<\/span>\n      <span class=\"o\">&lt;<\/span><span class=\"sr\">\/div<\/span><span class=\"err\">&gt;\n<\/span>    <span class=\"o\">&lt;<\/span><span class=\"sr\">\/Router<\/span><span class=\"err\">&gt;\n<\/span>  <span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"k\">default<\/span> <span class=\"nx\">App<\/span><span class=\"p\">;<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The App component is the entry point of the React application. It renders a Router component from React Router which defines the routes for the application. The Header and Footer components are also rendered inside the div tag with class name flex flex-col h-screen, and the main content is rendered inside the main tag with class name flex-1 overflow-y-auto. The Routes component from React Router maps the URLs to the appropriate components which are rendered using the element prop. The NoteList, NoteDetail, and NoteForm components are rendered based on the corresponding URLs: \/ for the NoteList, \/notes\/:id for the NoteDetail, and \/create and \/edit\/:id for the NoteForm.<\/p>\n\n<h1>\n  \n  \n  Configuring CORS\n<\/h1>\n\n<p>One common issue that can arise when making HTTP requests from a React application to a Django backend is the Cross-Origin Resource Sharing (CORS) error. This error occurs when the browser blocks a request because the domain or port of the requesting application does not match the domain or port of the server-side API.<\/p>\n\n<p>To avoid CORS errors, you can configure your Django backend to accept requests from the domain and port of your React application. One way to do this is to use the django-cors-headers package, which adds CORS headers to your Django responses, We do this by:<\/p>\n\n<p>*installing corsheaders:<br>\n<code>python -m pip install django-cors-headers<\/code><\/p>\n\n<p>*add it into our installed apps:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"n\">INSTALLED_APPS<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n    <span class=\"p\">...,<\/span>\n    <span class=\"sh\">\"<\/span><span class=\"s\">corsheaders<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"p\">...,<\/span>\n<span class=\"p\">]<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>*You will also need to add a middleware class to listen in on responses:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"n\">MIDDLEWARE<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n    <span class=\"p\">...,<\/span>\n    <span class=\"sh\">\"<\/span><span class=\"s\">corsheaders.middleware.CorsMiddleware<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">\"<\/span><span class=\"s\">django.middleware.common.CommonMiddleware<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"p\">...,<\/span>\n<span class=\"p\">]<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>*then we can configure the middleware's behaviour in your Django settings, for this tutorial we allow all origins:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"n\">CORS_ALLOW_ALL_ORIGINS<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">True<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Awesome with this now set up in the Django Api we can now use our React App to consume from our Rest Api.<br>\nLets start off both servers:<br>\n<strong>python<\/strong><br>\n<code>python manage.py runserver<\/code><\/p>\n\n<p><strong>javascript<\/strong><br>\n<code>npm run start<\/code><\/p>\n\n<h1>\n  \n  \n  Displaying our Front-end App\n<\/h1>\n\n<p>Great we can now see how our app looks like(from the client end):<\/p>\n\n<h2>\n  \n  \n  1.Our Home-Page Displaying all Notes:\n<\/h2>\n\n<p><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%2Fb8kvcue7ebjuhfotbyil.png\" class=\"article-body-image-wrapper\"><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%2Fb8kvcue7ebjuhfotbyil.png\" alt=\"GET\" width=\"800\" height=\"445\"><\/a><\/p>\n\n<p><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%2Fwj03sipjrdc0n3rky6dk.png\" class=\"article-body-image-wrapper\"><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%2Fwj03sipjrdc0n3rky6dk.png\" alt=\"CREATE\" width=\"800\" height=\"446\"><\/a><\/p>\n\n<blockquote>\n<p>Displays all Notes a user can click to view the specific note, the user can also create a new note and delete existing notes<\/p>\n<\/blockquote>\n\n<h3>\n  \n  \n  2.Our Note Detail:\n<\/h3>\n\n<p><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%2Fmlkqvs01hmogalq7n2rm.png\" class=\"article-body-image-wrapper\"><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%2Fmlkqvs01hmogalq7n2rm.png\" alt=\"GET NOTE\" width=\"800\" height=\"445\"><\/a><\/p>\n\n<p><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%2Fxhdeejh8cdoq6uxmxtnc.png\" class=\"article-body-image-wrapper\"><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%2Fxhdeejh8cdoq6uxmxtnc.png\" alt=\"EDIT\" width=\"800\" height=\"446\"><\/a><\/p>\n\n<blockquote>\n<p>Displays the specific note with more details whereas a user can be able to edit an existing note<\/p>\n<\/blockquote>\n\n<h3>\n  \n  \n  3.Header\n<\/h3>\n\n<p><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%2Fu87hdqc4aqybpzemcp84.png\" class=\"article-body-image-wrapper\"><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%2Fu87hdqc4aqybpzemcp84.png\" alt=\"Dark\" width=\"800\" height=\"446\"><\/a><\/p>\n\n<blockquote>\n<p>Our Header handles our funtionality for light\/dark mode as well as navigation back to homepage which is our NoteList<\/p>\n<\/blockquote>\n\n<p>In conclusion, we have successfully built the frontend of our web application using React and Tailwind CSS. We have learned how to create reusable components, manage state using hooks, and use Tailwind CSS classes to style our components. By leveraging the power of React and Tailwind, we have created a fast and responsive user interface for our app.<\/p>\n\n<p>I hope that you have enjoyed reading this article and have learned something new. I welcome your feedback and suggestions on how we can improve the code or approach. If you want to check out the source code for this project, it is available on GitHub <a href=\"https:\/\/github.com\/ki3ani\/studiosix\" rel=\"noopener noreferrer\">frontend<\/a>. Stay tuned for part 3 of the series where we will be focusing on authentication and authorization of our web app. Thank you for reading!<\/p>\n\n","category":"welcome"},{"title":"Building out a Notes App with React and a Django Rest API Part 1","pubDate":"Tue, 31 Jan 2023 09:06:54 +0000","link":"https:\/\/dev.to\/ki3ani\/building-out-a-notes-app-with-react-and-a-django-rest-api-part-1-5bc5","guid":"https:\/\/dev.to\/ki3ani\/building-out-a-notes-app-with-react-and-a-django-rest-api-part-1-5bc5","description":"<p>Building a modern web application can be a complex and challenging task. However, with the right tools and approach, it can also be an incredibly rewarding experience. In this article, we will be exploring how to build a full-stack application using the popular front-end library, React, and the powerful back-end framework, Django. Our focus will be on creating a simple yet powerful note-taking app that allows you to store, update, and delete your notes.<\/p>\n\n<p>We will start by setting up the development environment and then delve into building the back-end with Django, covering important topics such as models, views, and URL patterns. Next, we will move on to building the front-end with React, including topics such as components, state management, and integrating with the back-end.<\/p>\n\n<p>Finally, we will cover the deployment process, discussing how to host the app in a production environment and ensuring security and performance. By the end of this article, you will have a good understanding of how to build a complete React + Django application and have the skills to take your own projects to the next level. So, let's get started on building a feature-rich note-taking app!<\/p>\n\n<p>So starting off we will start up a Django project but first we have to ensure we are using a virtual environment, virtual environments are a crucial tool for maintaining the stability, compatibility, and reproducibility of your Python projects' we do this by:<\/p>\n\n<ul>\n<li>Assuming you have python installed already(<a href=\"https:\/\/www.python.org\/downloads\/\" rel=\"noopener noreferrer\">Link<\/a>) create a new folder where you want to put your project and open it up on your fave editor <\/li>\n<li>create a new python environment<\/li>\n<li>activate environment<\/li>\n<\/ul>\n\n<p><strong>Windows<\/strong><br>\n<code>py -m venv &lt;env-name&gt;<\/code><br>\n<code>&lt;env-name&gt;\\Scripts\\activate&gt;<\/code><\/p>\n\n<p><strong>Linux<\/strong><br>\n<code>virtualenv &lt;env-name&gt;<\/code><br>\n<code>source &lt;env-name&gt;\/bin\/activate<\/code><\/p>\n\n<p>This will activate my environment and we can now install Django by using pip which is the default package manager for Python, and is used to install and manage packages that can be used in your Python projects:<\/p>\n\n<p><code>pip install django<\/code><\/p>\n\n<p>We can then run:<\/p>\n\n<p><code>django-admin startproject &lt;project-name&gt;<\/code><\/p>\n\n<p>This will create a Folder with the project name you have given with all the files needed to start off your project courtesy of the Django Framework, move into your new project directory and to to test if everything is working fine run the command to start your server:<\/p>\n\n<p><code>python manage.py runserver<\/code><\/p>\n\n<p><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%2Fyf74bz8jn97az9n5avnr.png\" class=\"article-body-image-wrapper\"><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%2Fyf74bz8jn97az9n5avnr.png\" alt=\"runserver\" width=\"800\" height=\"438\"><\/a><br>\nThis confirms that your server is up and running<\/p>\n\n<p>We now move on to creating our API which we will use to make calls from the frontend, The concept of my app is similar to the regular Note App found on most modern phones nowadays that lets you track your notes in a CRUD-ely manner. We will first make a django app for the Api:<\/p>\n\n<p><code>Python manage.py startapp &lt;app-name&gt;<\/code><\/p>\n\n<p>Next, open settings.py file and input our project name in the INSTALLED_APPS list so that django can include it to the project<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># Application definition\n<\/span>\n<span class=\"n\">INSTALLED_APPS<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">django.contrib.admin<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">django.contrib.auth<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">django.contrib.contenttypes<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">django.contrib.sessions<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">django.contrib.messages<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">django.contrib.staticfiles<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">&lt;app-name&gt;.apps.ApiConfig<\/span><span class=\"sh\">'<\/span> <span class=\"c1\">#add it here\n<\/span><span class=\"p\">]<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Next we can set our URL paths for the main project, URL paths play a crucial role in how Django apps handle requests and display content to users. Open the main project urls.py and set the path as:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">django.contrib<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">admin<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">django.urls<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">path<\/span><span class=\"p\">,<\/span> <span class=\"n\">include<\/span>\n\n\n<span class=\"n\">urlpatterns<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n\n    <span class=\"nf\">path<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">admin\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">admin<\/span><span class=\"p\">.<\/span><span class=\"n\">site<\/span><span class=\"p\">.<\/span><span class=\"n\">urls<\/span><span class=\"p\">),<\/span>\n    <span class=\"nf\">path<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">&lt;app-name&gt;\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"nf\">include<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">&lt;app-name&gt;.urls<\/span><span class=\"sh\">'<\/span><span class=\"p\">))<\/span>\n\n<span class=\"p\">]<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Okay now the next step is to create our Note model based on the concept, In Django, models are used to represent the data that is stored in the app's database. A model defines the structure of the data, including the fields and their types, as well as any relationships to other models:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">django.db<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">models<\/span>\n\n<span class=\"c1\"># Create your models here.\n# This is the model for the notes\n<\/span><span class=\"k\">class<\/span> <span class=\"nc\">Note<\/span><span class=\"p\">(<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">Model<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">body<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">TextField<\/span><span class=\"p\">(<\/span><span class=\"n\">null<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span> <span class=\"n\">blank<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">created<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">DateTimeField<\/span><span class=\"p\">(<\/span><span class=\"n\">auto_now_add<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">updated<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">DateTimeField<\/span><span class=\"p\">(<\/span><span class=\"n\">auto_now<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\"># This is the string representation of the object\n<\/span>    <span class=\"k\">def<\/span> <span class=\"nf\">__str__<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">):<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">title<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Lets install Django rest framework and build out our api, Django REST framework (DRF) is a powerful and flexible toolkit for building Web APIs. DRF is a third-party package for Django that makes it easy to build, test, and debug RESTful APIs written using the Django framework, in your terminal<\/p>\n\n<p><code>pip install djangorestframework<\/code><\/p>\n\n<p>Next, we'll create a serializer for our model, This serializer will handle converting our model instance to and from JSON. Make a serializers.py file in the app folder and put in the following code:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">rest_framework<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">serializers<\/span> <span class=\"c1\"># Import the serializer class\n<\/span><span class=\"kn\">from<\/span> <span class=\"n\">.models<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Note<\/span>  <span class=\"c1\"># Import the Note model\n<\/span>\n<span class=\"c1\"># Create a serializer class\n# This class will convert the Note model into JSON\n<\/span><span class=\"k\">class<\/span> <span class=\"nc\">NoteSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">serializers<\/span><span class=\"p\">.<\/span><span class=\"n\">ModelSerializer<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">class<\/span> <span class=\"nc\">Meta<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">model<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Note<\/span>\n        <span class=\"n\">fields<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">'<\/span><span class=\"s\">__all__<\/span><span class=\"sh\">'<\/span>\n\n\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Next, we'll create Api views to handle our CRUD functionality we will use views.py and utils.py(create new file in the app folder), In a Django project, utility functions are often separated into their own module to keep the code organized and reusable, so in the utils.py we can have:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># This is the response that we will return\n<\/span><span class=\"kn\">from<\/span> <span class=\"n\">rest_framework.response<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Response<\/span>\n<span class=\"c1\"># This is the model that we will use\n<\/span><span class=\"kn\">from<\/span> <span class=\"n\">.models<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Note<\/span>\n<span class=\"c1\"># This is the serializer that we will use\n<\/span><span class=\"kn\">from<\/span> <span class=\"n\">.serializers<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">NoteSerializer<\/span>\n\n\n<span class=\"c1\"># This function will return the notes list\n<\/span><span class=\"k\">def<\/span> <span class=\"nf\">getNotesList<\/span><span class=\"p\">(<\/span><span class=\"n\">request<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">notes<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Note<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">all<\/span><span class=\"p\">().<\/span><span class=\"nf\">order_by<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">-updated<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">serializer<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">NoteSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">notes<\/span><span class=\"p\">,<\/span> <span class=\"n\">many<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">(<\/span><span class=\"n\">serializer<\/span><span class=\"p\">.<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n\n\n<span class=\"c1\"># This function will return the note detail\n<\/span><span class=\"k\">def<\/span> <span class=\"nf\">getNoteDetail<\/span><span class=\"p\">(<\/span><span class=\"n\">request<\/span><span class=\"p\">,<\/span> <span class=\"n\">pk<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">notes<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Note<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"nb\">id<\/span><span class=\"o\">=<\/span><span class=\"n\">pk<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">serializer<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">NoteSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">notes<\/span><span class=\"p\">,<\/span> <span class=\"n\">many<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">(<\/span><span class=\"n\">serializer<\/span><span class=\"p\">.<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\"># This function will create a note\n<\/span><span class=\"k\">def<\/span> <span class=\"nf\">createNote<\/span><span class=\"p\">(<\/span><span class=\"n\">request<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">data<\/span> <span class=\"o\">=<\/span> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">data<\/span>\n    <span class=\"n\">note<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Note<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">create<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">body<\/span><span class=\"o\">=<\/span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">body<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"n\">serializer<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">NoteSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">note<\/span><span class=\"p\">,<\/span> <span class=\"n\">many<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">(<\/span><span class=\"n\">serializer<\/span><span class=\"p\">.<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\"># This function will update a note\n<\/span><span class=\"k\">def<\/span> <span class=\"nf\">updateNote<\/span><span class=\"p\">(<\/span><span class=\"n\">request<\/span><span class=\"p\">,<\/span> <span class=\"n\">pk<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">data<\/span> <span class=\"o\">=<\/span> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">data<\/span>\n    <span class=\"n\">note<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Note<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"nb\">id<\/span><span class=\"o\">=<\/span><span class=\"n\">pk<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">serializer<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">NoteSerializer<\/span><span class=\"p\">(<\/span><span class=\"n\">instance<\/span><span class=\"o\">=<\/span><span class=\"n\">note<\/span><span class=\"p\">,<\/span> <span class=\"n\">data<\/span><span class=\"o\">=<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"n\">serializer<\/span><span class=\"p\">.<\/span><span class=\"nf\">is_valid<\/span><span class=\"p\">():<\/span>\n        <span class=\"n\">serializer<\/span><span class=\"p\">.<\/span><span class=\"nf\">save<\/span><span class=\"p\">()<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">(<\/span><span class=\"n\">serializer<\/span><span class=\"p\">.<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\"># This function will delete a note\n<\/span><span class=\"k\">def<\/span> <span class=\"nf\">deleteNote<\/span><span class=\"p\">(<\/span><span class=\"n\">request<\/span><span class=\"p\">,<\/span> <span class=\"n\">pk<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">note<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Note<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"nb\">id<\/span><span class=\"o\">=<\/span><span class=\"n\">pk<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">note<\/span><span class=\"p\">.<\/span><span class=\"nf\">delete<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nc\">Response<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">Note was deleted!<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n\n\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Next, we can now add our paths for our api by:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">django.urls<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">path<\/span> <span class=\"c1\"># This is the path function\n<\/span><span class=\"kn\">from<\/span> <span class=\"n\">.<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">views<\/span> <span class=\"c1\"># This is the views file\n<\/span>\n\n<span class=\"c1\"># This is the list of our routes\n<\/span><span class=\"n\">urlpatterns<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n    <span class=\"nf\">path<\/span><span class=\"p\">(<\/span><span class=\"sh\">''<\/span><span class=\"p\">,<\/span> <span class=\"n\">views<\/span><span class=\"p\">.<\/span><span class=\"n\">getRoutes<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">routes<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n    <span class=\"nf\">path<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">notes\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">views<\/span><span class=\"p\">.<\/span><span class=\"n\">getNotes<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">notes<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n    <span class=\"nf\">path<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">notes\/&lt;str:pk&gt;\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">views<\/span><span class=\"p\">.<\/span><span class=\"n\">getNote<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">note<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">]<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>We have now completed the functionality of our API and we can now be able to check it out using the Django Rest Framework that will installed earlier on, We first have to to make our database migrations to notify Django of the model that we have created and any changes that have taken place, then we can startup our server:<\/p>\n\n<p><strong>Migrations<\/strong><br>\n<code>python manage.py makemigrations<\/code><br>\n<code>python manage.py migrate<\/code><\/p>\n\n<p><strong>Start server<\/strong><br>\n<code>python manage.py runserver<\/code><\/p>\n\n<p>We expect to see our API up and running as such(remember to use the url path that you named your app):<\/p>\n\n<p><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%2F8riv0m1c0g4p9wp3rzt5.png\" class=\"article-body-image-wrapper\"><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%2F8riv0m1c0g4p9wp3rzt5.png\" alt=\"open-server\" width=\"800\" height=\"396\"><\/a><\/p>\n\n<p>Now we can see if our endpoints are working as expected, For the<br>\n(Api\/Notes) we have: <\/p>\n\n<p>1.<a href=\"http:\/\/127.0.0.1:8000\/api\/notes\/\" rel=\"noopener noreferrer\">GET<\/a> that will list all the notes:<\/p>\n\n<p><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%2Fnfe844n1pza9t9zmuh3f.png\" class=\"article-body-image-wrapper\"><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%2Fnfe844n1pza9t9zmuh3f.png\" alt=\"getNotes\" width=\"800\" height=\"403\"><\/a><\/p>\n\n<p>2.<a href=\"http:\/\/127.0.0.1:8000\/api\/notes\/\" rel=\"noopener noreferrer\">POST<\/a> that will let you create a new note:<\/p>\n\n<p><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%2Fajid1bcw6blxa42k1m4a.png\" class=\"article-body-image-wrapper\"><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%2Fajid1bcw6blxa42k1m4a.png\" alt=\"newNote\" width=\"800\" height=\"400\"><\/a><\/p>\n\n<p>And for the (Api\/Notes\/<a>str:pk<\/a>) we have:<\/p>\n\n<p>1.<a href=\"http:\/\/127.0.0.1:8000\/api\/notes\/10\/\" rel=\"noopener noreferrer\">GET<\/a> that will let you get the specific note:<\/p>\n\n<p><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%2Fb6rfuomzvnh0tsq94qma.png\" class=\"article-body-image-wrapper\"><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%2Fb6rfuomzvnh0tsq94qma.png\" alt=\"getNote\" width=\"800\" height=\"401\"><\/a><\/p>\n\n<p>2.<a href=\"http:\/\/127.0.0.1:8000\/api\/notes\/&lt;str:pk&gt;\/\" rel=\"noopener noreferrer\">UPDATE<\/a> that will let you update a specific note:<\/p>\n\n<p><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%2Fcd9g7ppu51jjj9pdyuzb.png\" class=\"article-body-image-wrapper\"><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%2Fcd9g7ppu51jjj9pdyuzb.png\" alt=\"Update\" width=\"800\" height=\"403\"><\/a><\/p>\n\n<p>3.<a href=\"http:\/\/127.0.0.1:8000\/api\/notes\/10\/\" rel=\"noopener noreferrer\">DELETE<\/a> that will delete the specific note:<\/p>\n\n<p><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%2F76zlv65b6r7mced2m8fa.png\" class=\"article-body-image-wrapper\"><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%2F76zlv65b6r7mced2m8fa.png\" alt=\"Delete\" width=\"800\" height=\"400\"><\/a><\/p>\n\n<h3>\n  \n  \n  Conclusion\n<\/h3>\n\n<p>In conclusion, Part 1 of our app-building journey has been a great success! We've learned how to create a basic API using Django and Django Rest Framework, but this is just the beginning. This API, though functional, is still in its earliest stages and needs refining. And for all you tech-savvy readers out there, feel free to star it, clone it, and take a closer look at the source code on my <a href=\"https:\/\/github.com\/ki3ani\/my-journal-backend\" rel=\"noopener noreferrer\">GitHub<\/a>. This is a great opportunity to not only learn, but also contribute to the project. Now, let's shift our focus to Part 2(coming soon :) ). We'll be making the front-end come to life with React, testing our creation, and launching it into the stratosphere with GCP. Get ready for an exciting journey ahead!<\/p>\n\n","category":["learning","productivity","discuss"]}]}}