<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Faruq Abdulsalam</title>
    <description>The latest articles on DEV Community by Faruq Abdulsalam (@nagatodev).</description>
    <link>https://dev.to/nagatodev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F690348%2F38b6a94f-f781-44a4-beca-cba421f7309c.jpeg</url>
      <title>DEV Community: Faruq Abdulsalam</title>
      <link>https://dev.to/nagatodev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nagatodev"/>
    <language>en</language>
    <item>
      <title>How to Invoke a Lambda Function via API Gateway Locally Using Terraform and LocalStack (PDF Generator – Part 3)</title>
      <dc:creator>Faruq Abdulsalam</dc:creator>
      <pubDate>Mon, 17 Feb 2025 09:17:11 +0000</pubDate>
      <link>https://dev.to/nagatodev/how-to-invoke-a-lambda-function-via-api-gateway-locally-using-terraform-and-localstack-pdf-4dbn</link>
      <guid>https://dev.to/nagatodev/how-to-invoke-a-lambda-function-via-api-gateway-locally-using-terraform-and-localstack-pdf-4dbn</guid>
      <description>&lt;p&gt;In my previous article, &lt;a href="https://dev.to/nagatodev/how-to-build-and-test-a-pdf-generator-lambda-using-localstack-on-your-local-machine-part-2-using-22fc"&gt;How to Build and Test a PDF Generator Lambda Using LocalStack on Your Local Machine (Part 2: Using Terraform)&lt;/a&gt;, we set up the foundational infrastructure, including &lt;code&gt;S3&lt;/code&gt;, &lt;code&gt;ECR&lt;/code&gt;, a &lt;code&gt;Lambda function&lt;/code&gt;, and an &lt;code&gt;IAM role&lt;/code&gt; using &lt;strong&gt;Terraform&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this part, we’ll take it further by integrating &lt;strong&gt;API Gateway&lt;/strong&gt; to invoke the &lt;code&gt;Lambda function&lt;/code&gt; locally using &lt;strong&gt;LocalStack&lt;/strong&gt;—allowing you to simulate real-world &lt;strong&gt;AWS&lt;/strong&gt; behavior entirely on your local machine. This is particularly useful when you need to trigger Lambda functions via &lt;strong&gt;HTTP&lt;/strong&gt;, just as you would in a production environment.&lt;/p&gt;

&lt;p&gt;I’ve kept this guide simple and practical, so all you need is some basic &lt;strong&gt;Terraform&lt;/strong&gt; knowledge to follow along.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before proceeding, ensure you have the following installed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Python 3.9+&lt;/li&gt;
&lt;li&gt;LocalStack account&lt;/li&gt;
&lt;li&gt;LocalStack CLI&lt;/li&gt;
&lt;li&gt;LocalStack Desktop&lt;/li&gt;
&lt;li&gt;Terraform&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;1. locals.tf&lt;/strong&gt;&lt;br&gt;
In this step, we'll introduce two new local variables specifically for the API Gateway resources. These variables define the names for the API Gateway and its deployment stage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;locals &lt;span class="o"&gt;{&lt;/span&gt;
  ...
  api_gateway_name       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"pdf-generator-api"&lt;/span&gt;
  api_gateway_stage_name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"prod"&lt;/span&gt;
  ...
&lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. main.tf&lt;/strong&gt;&lt;br&gt;
Add the following code blocks below to the &lt;code&gt;main.tf&lt;/code&gt; file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rest api&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resource &lt;span class="s2"&gt;"aws_api_gateway_rest_api"&lt;/span&gt; &lt;span class="s2"&gt;"lambda_api"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  name        &lt;span class="o"&gt;=&lt;/span&gt; local.api_gateway_name
  description &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"API Gateway for invoking the PDF Generator Lambda function"&lt;/span&gt;

  endpoint_configuration &lt;span class="o"&gt;{&lt;/span&gt;
    types &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"REGIONAL"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This block above creates the API Gateway &lt;code&gt;REST API&lt;/code&gt;. We assign its name using the local variable we defined earlier: &lt;code&gt;local.api_gateway_name&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The endpoint_configuration is set to REGIONAL, which is suitable because; we wont be using CloudFront and the API is not private(it will be accessible within the region).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;resource&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resource &lt;span class="s2"&gt;"aws_api_gateway_resource"&lt;/span&gt; &lt;span class="s2"&gt;"pdf_generator_api_root"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  rest_api_id &lt;span class="o"&gt;=&lt;/span&gt; aws_api_gateway_rest_api.lambda_api.id
  parent_id   &lt;span class="o"&gt;=&lt;/span&gt; aws_api_gateway_rest_api.lambda_api.root_resource_id
  path_part   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"generate-pdf"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This block creates a new API Gateway &lt;code&gt;resource&lt;/code&gt;, linking it to the previously created REST API using &lt;code&gt;rest_api_id&lt;/code&gt;. We also define the &lt;code&gt;parent_id&lt;/code&gt; and set the path to &lt;code&gt;/generate-pdf&lt;/code&gt;, which establishes the resource's URL path under the API Gateway.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;method&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resource &lt;span class="s2"&gt;"aws_api_gateway_method"&lt;/span&gt; &lt;span class="s2"&gt;"pdf_generator_api_method"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  rest_api_id      &lt;span class="o"&gt;=&lt;/span&gt; aws_api_gateway_rest_api.lambda_api.id
  resource_id      &lt;span class="o"&gt;=&lt;/span&gt; aws_api_gateway_resource.pdf_generator_api_root.id
  http_method      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"POST"&lt;/span&gt;
  authorization    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"NONE"&lt;/span&gt;
  api_key_required &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This block creates the method for the resource above. It links the method to the REST API as well as the resource, and specifies the HTTP method as POST. Since we don't need authorization or an API key in this case, we set them to "NONE" and false, respectively.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;integration&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resource &lt;span class="s2"&gt;"aws_api_gateway_integration"&lt;/span&gt; &lt;span class="s2"&gt;"pdf_generator_api_integration"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  rest_api_id &lt;span class="o"&gt;=&lt;/span&gt; aws_api_gateway_rest_api.lambda_api.id
  resource_id &lt;span class="o"&gt;=&lt;/span&gt; aws_api_gateway_resource.pdf_generator_api_root.id
  http_method &lt;span class="o"&gt;=&lt;/span&gt; aws_api_gateway_method.pdf_generator_api_method.http_method

  &lt;span class="nb"&gt;type&lt;/span&gt;                    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AWS_PROXY"&lt;/span&gt;
  integration_http_method &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"POST"&lt;/span&gt;
  uri                     &lt;span class="o"&gt;=&lt;/span&gt; aws_lambda_function.pdf_generator.invoke_arn

  depends_on &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;aws_lambda_function.pdf_generator]

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This block creates the integration for the method above, linking it to the REST API, the resource, and the HTTP method. It specifies an &lt;code&gt;AWS_PROXY&lt;/code&gt; integration type, which allows direct communication between API Gateway and the Lambda function. The integration &lt;code&gt;HTTP&lt;/code&gt; method is set to POST, and the URI points to the Lambda function’s invoke ARN. The &lt;code&gt;depends_on&lt;/code&gt; attribute ensures that the Lambda function is created before the integration is established.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;deployment&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resource &lt;span class="s2"&gt;"aws_api_gateway_deployment"&lt;/span&gt; &lt;span class="s2"&gt;"lambda_api_deployment"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  rest_api_id &lt;span class="o"&gt;=&lt;/span&gt; aws_api_gateway_rest_api.lambda_api.id
  stage_name  &lt;span class="o"&gt;=&lt;/span&gt; local.api_gateway_stage_name

  lifecycle &lt;span class="o"&gt;{&lt;/span&gt;
    create_before_destroy &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  triggers &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    redeployment &lt;span class="o"&gt;=&lt;/span&gt; sha1&lt;span class="o"&gt;(&lt;/span&gt;jsonencode&lt;span class="o"&gt;([&lt;/span&gt;
      aws_api_gateway_resource.pdf_generator_api_root.id,
      aws_api_gateway_method.pdf_generator_api_method.id,
      aws_api_gateway_integration.pdf_generator_api_integration.id
    &lt;span class="o"&gt;]))&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  depends_on &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
    aws_api_gateway_integration.pdf_generator_api_integration
  &lt;span class="o"&gt;]&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This block creates a deployment for the API, linking it to the REST API and specifying the stage name, which was declared earlier as a local variable. The &lt;code&gt;lifecycle&lt;/code&gt; block ensures that the deployment is created before any resources are destroyed, minimizing downtime. The &lt;code&gt;triggers&lt;/code&gt; attribute uses a SHA1 hash of the resource, method, and integration IDs to trigger a redeployment when changes occur. The &lt;code&gt;depends_on&lt;/code&gt; attribute ensures that the deployment happens only after the API integration is fully created.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;permission&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resource &lt;span class="s2"&gt;"aws_lambda_permission"&lt;/span&gt; &lt;span class="s2"&gt;"apigw_lambda_permission"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  action        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"lambda:InvokeFunction"&lt;/span&gt;
  function_name &lt;span class="o"&gt;=&lt;/span&gt; aws_lambda_function.pdf_generator.function_name
  principal     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"apigateway.amazonaws.com"&lt;/span&gt;
  source_arn    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;aws_api_gateway_rest_api&lt;/span&gt;&lt;span class="p"&gt;.lambda_api.execution_arn&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.api_gateway_stage_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/*"&lt;/span&gt;

  lifecycle &lt;span class="o"&gt;{&lt;/span&gt;
    replace_triggered_by &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;aws_lambda_function.pdf_generator]
  &lt;span class="o"&gt;}&lt;/span&gt;

  depends_on &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;aws_lambda_function.pdf_generator, aws_api_gateway_deployment.lambda_api_deployment]
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This block grants the necessary permission for the API Gateway endpoint to invoke the Lambda function. The &lt;code&gt;action&lt;/code&gt; is set to &lt;code&gt;"lambda:InvokeFunction"&lt;/code&gt;, allowing the API Gateway to trigger the Lambda. The &lt;code&gt;source_arn&lt;/code&gt; specifies the ARN of the API Gateway’s execution role and stage. The &lt;code&gt;lifecycle&lt;/code&gt; block ensures that the permission is replaced if the Lambda function changes, and the &lt;code&gt;depends_on&lt;/code&gt; attribute ensures the permission is created only after the Lambda function and API Gateway deployment are in place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. outputs.tf&lt;/strong&gt;&lt;br&gt;
Finally, create a new file named &lt;code&gt;outputs.tf&lt;/code&gt; in the root of the &lt;code&gt;infrastructure&lt;/code&gt; directory and add this content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;output &lt;span class="s2"&gt;"rest_api_url"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  description &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The URL of the API Gateway REST API"&lt;/span&gt;
  value       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;aws_api_gateway_rest_api&lt;/span&gt;&lt;span class="p"&gt;.lambda_api.id&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.execute-api.localhost.localstack.cloud:4566/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.api_gateway_stage_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This block creates an output for the URL of the API Gateway REST API. Normally, the URL follows the format: &lt;code&gt;https://{rest_api_id}.execute-api.{region}.amazonaws.com/{stage_name}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, since we're working with LocalStack in our local environment, the URL format is slightly different. It omits the &lt;code&gt;region&lt;/code&gt; and &lt;code&gt;amazonaws.com&lt;/code&gt; parts, and instead uses &lt;code&gt;localhost.localstack.cloud&lt;/code&gt; as the &lt;code&gt;base domain&lt;/code&gt;. This allows us to interact with the API locally.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;rest_api_id&lt;/code&gt; is simply the ID of the REST API, and there’s no difference in how it's used here. The &lt;code&gt;stage_name&lt;/code&gt; corresponds to the local variable defined earlier in the &lt;code&gt;locals.tf&lt;/code&gt; file&lt;/p&gt;




&lt;p&gt;At this point, we have completed the code needed to provision the API Gateway resources and retrieve the URL. The next step is to create the resources and test our new implementation.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;tflocal plan&lt;/code&gt; to get an overview of all the AWS resources that will be created. Then, run &lt;code&gt;tflocal apply&lt;/code&gt; to confirm and initiate the creation of the resources.&lt;/p&gt;

&lt;p&gt;Afterward, you should see the output of your API Gateway URL in the terminal. As explained earlier, the URL will have a format similar to this: &lt;code&gt;https://{your_rest_api_id}.execute-api.localhost.localstack.cloud:4566/prod&lt;/code&gt;&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;Invoke lambda function&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To test the Lambda function, we won’t invoke it directly. Instead, we will use the URL mentioned above. You can use &lt;strong&gt;Postman&lt;/strong&gt; to make a &lt;code&gt;POST&lt;/code&gt; request to &lt;code&gt;https://{your_rest_api_id}.execute-api.localhost.localstack.cloud:4566/prod/generate-pdf&lt;/code&gt; (API Gateway URL + the path to the resource we created &lt;code&gt;generate-pdf&lt;/code&gt; ) with the following payload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"first_name"&lt;/span&gt;: &lt;span class="s2"&gt;"John"&lt;/span&gt;, &lt;span class="s2"&gt;"last_name"&lt;/span&gt;: &lt;span class="s2"&gt;"Doe"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the same payload we previously used with the event.json file.&lt;/p&gt;

&lt;p&gt;Alternatively, you can use &lt;strong&gt;curl&lt;/strong&gt; to make the request. Here's the &lt;code&gt;curl&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://&lt;span class="o"&gt;{&lt;/span&gt;your_rest_api_id&lt;span class="o"&gt;}&lt;/span&gt;.execute-api.localhost.localstack.cloud:4566/prod/generate-pdf &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"first_name": "John", "last_name": "Doe"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the success message below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"message"&lt;/span&gt;: &lt;span class="s2"&gt;"PDF generated and uploaded successfully!"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can confirm that the &lt;code&gt;PDF&lt;/code&gt; was successfully generated and stored in the &lt;code&gt;S3 bucket&lt;/code&gt; by navigating to the bucket via the &lt;code&gt;LocalStack Desktop&lt;/code&gt; and downloading the PDF.&lt;/p&gt;




&lt;p&gt;Congratulations! 🎉&lt;/p&gt;

&lt;p&gt;You’ve successfully set up your API Gateway, linked it to your Lambda function, and tested it locally using Terraform and LocalStack—all without needing an AWS account. Thanks for reading!&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>aws</category>
      <category>terraform</category>
      <category>apigateway</category>
    </item>
    <item>
      <title>How to Build and Test a PDF Generator Lambda Using LocalStack on Your Local Machine (Part 2: Using Terraform)</title>
      <dc:creator>Faruq Abdulsalam</dc:creator>
      <pubDate>Wed, 29 Jan 2025 10:09:25 +0000</pubDate>
      <link>https://dev.to/nagatodev/how-to-build-and-test-a-pdf-generator-lambda-using-localstack-on-your-local-machine-part-2-using-22fc</link>
      <guid>https://dev.to/nagatodev/how-to-build-and-test-a-pdf-generator-lambda-using-localstack-on-your-local-machine-part-2-using-22fc</guid>
      <description>&lt;p&gt;This article is a follow-up to my previous post, article &lt;a href="https://dev.to/nagatodev/how-to-build-and-test-a-pdf-generator-lambda-using-localstack-on-your-local-machine-53md"&gt;&lt;strong&gt;How to Build and Test a PDF Generator Lambda Using LocalStack on Your Local Machine&lt;/strong&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In that article, I walked you through how to build and test a PDF generator Lambda function locally using mock AWS services—&lt;strong&gt;AWS Lambda, Elastic Container Registry (ECR), and S3 buckets&lt;/strong&gt;—via &lt;strong&gt;LocalStack&lt;/strong&gt;. We used the &lt;code&gt;awslocal&lt;/code&gt; CLI to provision the required infrastructure.&lt;/p&gt;

&lt;p&gt;In this follow-up, we'll take a different approach. Instead of using the CLI, we'll use &lt;strong&gt;Terraform&lt;/strong&gt;, an Infrastructure as Code (IaC) tool, to provision our resources. This guide will be simple and straightforward, so &lt;strong&gt;basic Terraform experience is all you need&lt;/strong&gt; to follow along.&lt;/p&gt;

&lt;p&gt;If you haven’t read the &lt;a href="https://dev.to/nagatodev/how-to-build-and-test-a-pdf-generator-lambda-using-localstack-on-your-local-machine-53md"&gt;previous article&lt;/a&gt; yet, I highly recommend checking it out first as it covers the &lt;strong&gt;PDF generation logic itself&lt;/strong&gt;, which we won’t be repeating here.&lt;/p&gt;

&lt;p&gt;Let's get started&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before proceeding, ensure you have the following installed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Python 3.9+&lt;/li&gt;
&lt;li&gt;LocalStack account&lt;/li&gt;
&lt;li&gt;LocalStack CLI&lt;/li&gt;
&lt;li&gt;LocalStack Desktop&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;1: Restart the LocalStack Container&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To ensure a clean environment and avoid any conflicts with previously provisioned services, you need to restart your LocalStack container. This step is important because it allows us to reuse the resource names used in the last article.&lt;/p&gt;

&lt;p&gt;You can terminate the currently running container by pressing &lt;code&gt;CTRL + C&lt;/code&gt; command , or you can stop the container directly using the &lt;strong&gt;LocalStack Desktop&lt;/strong&gt; application. Then restart the container by running this command &lt;code&gt;DEBUG=1 localstack start&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Install the terraform-local package&lt;/strong&gt;&lt;br&gt;
In the root directory named &lt;code&gt;localstack&lt;/code&gt;, please activate your virtual environment if it is not already active. &lt;/p&gt;

&lt;p&gt;Then, install the &lt;code&gt;terraform-local&lt;/code&gt; package, which is a wrapper script that allows you to use Terraform to deploy resources to your LocalStack environment. This tool simplifies using Terraform locally with LocalStack, providing a smooth integration between the two.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Creating Infrastructure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next, create a new folder called &lt;code&gt;infrastructure&lt;/code&gt;. This folder will house the following files:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;locals.tf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;versions.tf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;main.tf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scripts/build_and_push_lambda_image.sh&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's take a closer look at each of these files and their roles in setting up the infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. locals.tf&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;locals &lt;span class="o"&gt;{&lt;/span&gt;
  aws_region      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eu-west-1"&lt;/span&gt;
  pdf_bucket_name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-pdf-bucket"&lt;/span&gt;
  pdf_ecr_name    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"pdf-generator-image"&lt;/span&gt;
  pdf_generator_lambda &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    function_name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"pdf-generator-lambda"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the locals.tf file, we define some basic variables that will be used throughout our Terraform configuration. Here, we specify the AWS region, the name of the S3 bucket, the name of the ECR repository, and the Lambda function name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. versions.tf&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform &lt;span class="o"&gt;{&lt;/span&gt;
  required_providers &lt;span class="o"&gt;{&lt;/span&gt;
    aws &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;source&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hashicorp/aws"&lt;/span&gt;
      version &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 5.59.0"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    random &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;source&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hashicorp/random"&lt;/span&gt;
      version &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 3.6.2"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

provider &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  region &lt;span class="o"&gt;=&lt;/span&gt; local.aws_region

&lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;versions.tf&lt;/code&gt; file, we specify the required providers for our Terraform configuration. We define the AWS provider (hashicorp/aws) to interact with AWS services, and the random provider (hashicorp/random) to generate random values like unique IDs. We also configure the AWS provider to use the region defined in the &lt;code&gt;locals.tf&lt;/code&gt; file (&lt;code&gt;local.aws_region&lt;/code&gt;). This file ensures that Terraform uses the correct providers and versions when provisioning infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. main.tf&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;S3 Bucket&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Generate random string for the bucket name&lt;/span&gt;
resource &lt;span class="s2"&gt;"random_id"&lt;/span&gt; &lt;span class="s2"&gt;"pdf_bucket_suffix"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  byte_length &lt;span class="o"&gt;=&lt;/span&gt; 6
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# S3 bucket for storing the generated PDF files&lt;/span&gt;
resource &lt;span class="s2"&gt;"aws_s3_bucket"&lt;/span&gt; &lt;span class="s2"&gt;"pdf_bucket"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  bucket        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.pdf_bucket_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;random_id&lt;/span&gt;&lt;span class="p"&gt;.pdf_bucket_suffix.hex&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  force_destroy &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true

  &lt;/span&gt;lifecycle &lt;span class="o"&gt;{&lt;/span&gt;
    prevent_destroy &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  tags &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    Name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.pdf_bucket_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We first create a &lt;code&gt;random_id&lt;/code&gt; resource to generate a random string, which will be appended to the name of the S3 bucket, ensuring it is unique. The &lt;code&gt;byte_length = 6&lt;/code&gt; specifies the length of the random string. Then the &lt;code&gt;aws_s3_bucket&lt;/code&gt; resource is created using the bucket name defined by the local variable (&lt;code&gt;local.pdf_bucket_name&lt;/code&gt;) combined with the random suffix. We also configure the bucket to allow forced destruction (&lt;code&gt;force_destroy = true&lt;/code&gt;) which means it can be deleted even if it contains objects. Finally, the lifecycle block includes &lt;code&gt;prevent_destroy = false&lt;/code&gt; setting, which ensures that Terraform won’t block the destruction of the bucket if needed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Elastic Container Registry&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ECR repository for storing the Docker images&lt;/span&gt;
resource &lt;span class="s2"&gt;"aws_ecr_repository"&lt;/span&gt; &lt;span class="s2"&gt;"pdf_generator_ecr"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  name &lt;span class="o"&gt;=&lt;/span&gt; local.pdf_ecr_name
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;aws_ecr_repository&lt;/code&gt; resource is used to create an ECR repository where the Docker image for the Lambda function will be stored. The repository name is defined using the local variable &lt;code&gt;local.pdf_ecr_name&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Build and Push Image to ECR&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run your existing image push script using null_resource&lt;/span&gt;
resource &lt;span class="s2"&gt;"null_resource"&lt;/span&gt; &lt;span class="s2"&gt;"run_build_and_push_image_script"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  provisioner &lt;span class="s2"&gt;"local-exec"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bash &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.module&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/scripts/build_and_push_lambda_image.sh"&lt;/span&gt;
    environment &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      ECR_REPO_URI &lt;span class="o"&gt;=&lt;/span&gt; aws_ecr_repository.pdf_generator_ecr.repository_url
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  depends_on &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
    aws_ecr_repository.pdf_generator_ecr &lt;span class="c"&gt;# Ensure the repository exists before running the script&lt;/span&gt;
  &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Since we cannot create an empty lambda function, we would have to ensure we have an existing image before the lambda function itself is created. So we can do that using the &lt;code&gt;null_resource&lt;/code&gt; block to call our  script &lt;code&gt;scripts/build_and_push_lambda_image.sh&lt;/code&gt; that'll build the Docker image for our pdf generator function and deploys it to the ECR repository defined in the configuration. We'll add content to the script after completing the main.tf file.&lt;/p&gt;

&lt;p&gt;In this &lt;code&gt;null_resource&lt;/code&gt; block, we pass the &lt;code&gt;ECR_REPO_URI&lt;/code&gt; environment variable to the &lt;code&gt;build_and_push_lambda_image.sh&lt;/code&gt; script, which allows it to dynamically use the correct Amazon ECR repository URL for pushing the built Docker image. The &lt;code&gt;depends_on&lt;/code&gt; array ensures that the script runs only after the ECR repository (&lt;code&gt;aws_ecr_repository.pdf_generator_ecr&lt;/code&gt;) is created, preventing any issues from attempting to push an image to a non-existent repository. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; The approach used in this tutorial is for educational purposes only. While Terraform is a powerful tool for provisioning infrastructure, using it to build and push Docker images is not advisable for production environments. In production, it's best to use a dedicated CI/CD pipeline to manage your application artifacts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IAM role
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# IAM Role for Lambda Execution&lt;/span&gt;
resource &lt;span class="s2"&gt;"aws_iam_role"&lt;/span&gt; &lt;span class="s2"&gt;"pdf_generator_lambda_role"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ExecRole-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.pdf_generator_lambda.function_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  assume_role_policy &lt;span class="o"&gt;=&lt;/span&gt; jsonencode&lt;span class="o"&gt;({&lt;/span&gt;
    Version &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;
    Statement &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
      &lt;span class="o"&gt;{&lt;/span&gt;
        Action &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sts:AssumeRole"&lt;/span&gt;
        Effect &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
        Sid    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
        Principal &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          Service &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"lambda.amazonaws.com"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;aws_iam_role.pdf_generator_lambda_role&lt;/code&gt; IAM role allows the Lambda function to assume the necessary permissions for execution. It grants the Lambda service permission to interact with AWS resources securely by defining the &lt;code&gt;assume_role_policy&lt;/code&gt; with the appropriate permissions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Lambda function&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Lambda Function for PDF Generation&lt;/span&gt;
resource &lt;span class="s2"&gt;"aws_lambda_function"&lt;/span&gt; &lt;span class="s2"&gt;"pdf_generator"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  function_name &lt;span class="o"&gt;=&lt;/span&gt; local.pdf_generator_lambda.function_name
  role          &lt;span class="o"&gt;=&lt;/span&gt; aws_iam_role.pdf_generator_lambda_role.arn
  package_type  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Image"&lt;/span&gt;
  image_uri     &lt;span class="o"&gt;=&lt;/span&gt; aws_ecr_repository.pdf_generator_ecr.repository_url
  &lt;span class="nb"&gt;timeout&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; 60
  memory_size   &lt;span class="o"&gt;=&lt;/span&gt; 128
  architectures &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"arm64"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

  environment &lt;span class="o"&gt;{&lt;/span&gt;
    variables &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      S3_BUCKET_NAME &lt;span class="o"&gt;=&lt;/span&gt; aws_s3_bucket.pdf_bucket.bucket
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  depends_on &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
    aws_ecr_repository.pdf_generator_ecr,         &lt;span class="c"&gt;# Ensure the ECR repo exists before pushing the image&lt;/span&gt;
    null_resource.run_build_and_push_image_script &lt;span class="c"&gt;# Ensure the script runs before Lambda is created&lt;/span&gt;
  &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we define the &lt;code&gt;pdf_generator&lt;/code&gt; Lambda function, specifying the function name, IAM role, and container image from the ECR repository. The Lambda is allocated 128MB of memory and a 60-second timeout, using &lt;code&gt;arm64&lt;/code&gt; architecture. We set an environment variable for the S3 bucket name. The &lt;code&gt;depends_on&lt;/code&gt; block ensures that the Lambda is created only after the ECR repository exists and the Docker image is built and pushed. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If your local development machine or the environment where you’re building the Lambda function uses a different architecture, such as &lt;code&gt;x86_64&lt;/code&gt; (common for many Linux or Windows machines), you can adjust the &lt;code&gt;architectures&lt;/code&gt; array value from &lt;code&gt;arm64&lt;/code&gt; to &lt;code&gt;x86_64&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. scripts/build_and_push_lambda_image.sh&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Get the ECR URI from the environment variable&lt;/span&gt;
&lt;span class="nv"&gt;ECR_REPO_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$ECR_REPO_URI&lt;/span&gt;

&lt;span class="c"&gt;# Now you can use the $ECR_REPO_URI in the script&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"ECR URI: &lt;/span&gt;&lt;span class="nv"&gt;$ECR_REPO_URI&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# get the current directory&lt;/span&gt;
&lt;span class="nv"&gt;SCRIPT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASH_SOURCE&lt;/span&gt;&lt;span class="p"&gt;[0]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;pwd&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Navigate to the lambda function directory&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Navigating to lambda function directory..."&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$SCRIPT_DIR&lt;/span&gt;/../../pdf-generator-lambda &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Current directory: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Build the docker image&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Building the docker image..."&lt;/span&gt;
docker build &lt;span class="nt"&gt;--no-cache&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; lambda-container-image &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Tag the image with the ECR repository URI&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Tagging the docker image with the ECR repository URI..."&lt;/span&gt;
docker tag lambda-container-image &lt;span class="nv"&gt;$ECR_REPO_URI&lt;/span&gt;

&lt;span class="c"&gt;# Push the image to the ECR repository&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Pushing the docker image to the ECR repository..."&lt;/span&gt;
docker push &lt;span class="nv"&gt;$ECR_REPO_URI&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Script execution completed."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script builds the PDF generator Lambda function as a Docker image, tags it, and pushes it to the specified ECR repository. The &lt;code&gt;ECR_REPO_URI&lt;/code&gt; is passed as an environment variable from the &lt;code&gt;null_resource&lt;/code&gt; block in the &lt;code&gt;main.tf&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;This completes the necessary Terraform configuration. Before we proceed to create the infrastructure using the installed &lt;code&gt;tflocal&lt;/code&gt; package, let's make a small change to the &lt;code&gt;upload_file.py&lt;/code&gt; script that handles uploading the generated PDF file to the S3 bucket. Previously, we hardcoded the &lt;code&gt;bucket-name&lt;/code&gt;; now, we'll retrieve it from the environment as an environment variable instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;upload_file.py&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

.....
S3_BUCKET_NAME &lt;span class="o"&gt;=&lt;/span&gt; os.environ.get&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"S3_BUCKET_NAME"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Import the &lt;code&gt;os&lt;/code&gt; module and modify the line above so that the script uses the &lt;code&gt;S3_BUCKET_NAME&lt;/code&gt; environment variable instead of relying on a hardcoded value.&lt;/p&gt;

&lt;p&gt;Now we are ready to create our infrastructure. From inside the &lt;code&gt;infrastructure&lt;/code&gt; directory, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tflocal init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will initialize Terraform and generate some files once it runs successfully. Next, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tflocal plan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will return an overview of all the AWS resources that will be provisioned and set up in the active LocalStack container. You should see a line similar to: &lt;em&gt;Plan: 6 to add, 0 to change, 0 to destroy&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Finally, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tflocal apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to create the resources. This will display an overview similar to what you saw earlier when running &lt;code&gt;tflocal plan&lt;/code&gt;, and it will ask you to confirm whether you want to proceed. Simply type &lt;code&gt;yes&lt;/code&gt;, and all your resources will be created in LocalStack. For a sanity check, you can use either the AWS CLI or the LocalStack Desktop to verify that the following resources have been created: &lt;code&gt;S3 bucket&lt;/code&gt;, &lt;code&gt;ECR repo&lt;/code&gt;, and &lt;code&gt;Lambda function&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, let's invoke our Lambda function. Navigate back to the &lt;code&gt;pdf-generator-lambda&lt;/code&gt; directory and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;awslocal lambda invoke &lt;span class="nt"&gt;--function-name&lt;/span&gt; pdf-generator-lambda &lt;span class="nt"&gt;--payload&lt;/span&gt; file://event.json /tmp/lambda.out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should receive a success message like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"StatusCode"&lt;/span&gt;: 200,
    &lt;span class="s2"&gt;"ExecutedVersion"&lt;/span&gt;: &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LATEST&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can confirm that the PDF was successfully generated and stored in the S3 bucket by navigating to the bucket via the LocalStack Desktop and downloading the PDF.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Congratulations! 🎉&lt;/strong&gt;&lt;br&gt;
You’ve successfully set up and tested your infrastructure using Terraform and LocalStack. Thank you for reading!&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>aws</category>
      <category>docker</category>
      <category>terraform</category>
    </item>
    <item>
      <title>How to Build and Test a PDF Generator Lambda Using LocalStack on Your Local Machine</title>
      <dc:creator>Faruq Abdulsalam</dc:creator>
      <pubDate>Thu, 16 Jan 2025 09:46:06 +0000</pubDate>
      <link>https://dev.to/nagatodev/how-to-build-and-test-a-pdf-generator-lambda-using-localstack-on-your-local-machine-53md</link>
      <guid>https://dev.to/nagatodev/how-to-build-and-test-a-pdf-generator-lambda-using-localstack-on-your-local-machine-53md</guid>
      <description>&lt;p&gt;Have you ever struggled with adding a PDF generation feature to your application? I’ve certainly faced that pain more than a few times. Whether it’s generating receipts, weekly or monthly reports, or just about anything else, PDF generation is a feature that seems to pop up in almost every project I’ve worked on. Technology is fascinating, and users are always pushing for features that make their lives easier—and let’s face it, users are always right 😉.&lt;/p&gt;

&lt;p&gt;In this part of the series, I’ll walk you through how to easily create a Lambda function that handles PDF generation. We’ll build the function as a Docker image, push it to the local Elastic Container Registry (ECR) service within LocalStack, and then test it locally. To validate the generated PDF, we’ll also integrate the local S3 service in LocalStack. This setup enables you to develop, test, and debug your Lambda function entirely on your local machine before deploying it to the AWS cloud.&lt;/p&gt;

&lt;p&gt;If you haven’t already read my previous article on working with AWS S3 locally using LocalStack, I highly recommend giving it a read. It covers the setup of both the LocalStack environment and your development environment, along with easy steps for working with AWS S3 in LocalStack. In this article, we'll be building on that foundation as we create a Lambda function for PDF generation and integrate it with LocalStack’s S3 service. You can find that previous article &lt;a href="https://dev.to/nagatodev/how-to-simulate-aws-s3-on-your-local-machine-with-localstack-53dl"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Buckle up and enjoy the ride!&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Python 3.9+&lt;/li&gt;
&lt;li&gt;LocalStack account&lt;/li&gt;
&lt;li&gt;LocalStack CLI&lt;/li&gt;
&lt;li&gt;LocalStack Desktop&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  FILES and CODE
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Let's Start Coding!&lt;/strong&gt; In this section, we will create a few essential files that will allow us to build and test our Lambda function for generating PDFs and uploading them to S3 using LocalStack.&lt;/p&gt;

&lt;p&gt;We'll create a new directory called &lt;code&gt;pdf-generator-lambda&lt;/code&gt; inside the &lt;code&gt;localstack&lt;/code&gt; directory, where you previously set up your virtual environment. This new directory will contain the following files:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;requirements.txt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Dockerfile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;logger.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pdf_generator.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lambda_function.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;event.json&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;&lt;code&gt;templates/test.html&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;upload_file.py&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's walk through each of these files and their role in the project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. requirements.txt&lt;/strong&gt;&lt;br&gt;
This file lists the Python dependencies required for our Lambda function. These dependencies include:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Jinja2&lt;/code&gt;: A templating engine that allows you to create dynamic templates.&lt;br&gt;
&lt;code&gt;pdfkit&lt;/code&gt;: A Python wrapper for the &lt;code&gt;wkhtmltopdf&lt;/code&gt; tool that converts HTML to PDFs.&lt;br&gt;
&lt;code&gt;boto3&lt;/code&gt;: The AWS SDK for Python, which is used to interact with AWS services such as S3.&lt;br&gt;
&lt;code&gt;botocore&lt;/code&gt;: A low-level, foundational library for interacting with AWS APIs, required by boto3.&lt;/p&gt;

&lt;p&gt;Here’s the content for &lt;code&gt;requirements.txt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;Jinja2&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;3.1.4
&lt;span class="nv"&gt;pdfkit&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;1.0.0
&lt;span class="nv"&gt;boto3&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;1.26.146
&lt;span class="nv"&gt;botocore&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;1.29.146
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Dockerfile&lt;/strong&gt;&lt;br&gt;
The &lt;code&gt;Dockerfile&lt;/code&gt; defines how the Lambda function will be packaged as a Docker container. It sets up the environment, installs dependencies, and copies the necessary files for your Lambda function. Here’s a breakdown of the Dockerfile:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Base Image&lt;/code&gt;: We’re using the official &lt;code&gt;public.ecr.aws/lambda/python:3.10&lt;/code&gt; base image for Lambda functions with &lt;code&gt;Python 3.10&lt;/code&gt;. This image is pre-configured to run AWS Lambda functions.&lt;br&gt;
&lt;code&gt;Installing Dependencies&lt;/code&gt;: We install &lt;code&gt;wkhtmltopdf&lt;/code&gt; with the correct binaries for either &lt;code&gt;x86_64&lt;/code&gt; or &lt;code&gt;aarch64&lt;/code&gt; architecture to ensure compatibility and other necessary tools that the Lambda function will need to generate PDFs.&lt;br&gt;
&lt;code&gt;Copying Code&lt;/code&gt;: We copy the Python files from the local environment into the Docker container.&lt;br&gt;
&lt;code&gt;Lambda Handler&lt;/code&gt;: The entry point of the Lambda function is defined as &lt;code&gt;lambda_function.lambda_handler&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here’s the content for the Dockerfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;FROM public.ecr.aws/lambda/python:3.10

&lt;span class="c"&gt;# Install necessary tools and clean up&lt;/span&gt;
RUN yum &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;gcc gcc-c++ unzip which &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; yum clean all &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/cache/yum

&lt;span class="c"&gt;# Set the Lambda task root explicitly&lt;/span&gt;
ENV &lt;span class="nv"&gt;LAMBDA_TASK_ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/task

&lt;span class="c"&gt;# Copy and install Python dependencies&lt;/span&gt;
COPY ./requirements.txt &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LAMBDA_TASK_ROOT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
RUN pip3 &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--upgrade&lt;/span&gt; pip &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pip3 &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="c"&gt;# Install wkhtmltopdf with architecture-specific binaries&lt;/span&gt;
RUN &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ARCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"x86_64"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        curl &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; wkhtmltopdf.rpm &lt;span class="s2"&gt;"https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox-0.12.6-1.amazonlinux2.x86_64.rpm"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ARCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aarch64"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        curl &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; wkhtmltopdf.rpm &lt;span class="s2"&gt;"https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox-0.12.6-1.amazonlinux2.aarch64.rpm"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; yum &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;wkhtmltopdf.rpm &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; wkhtmltopdf.rpm

&lt;span class="c"&gt;# Optionally move wkhtmltopdf to /opt/bin and set permissions&lt;/span&gt;
RUN &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /opt/bin &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;mv&lt;/span&gt; /usr/local/bin/wkhtmltopdf /opt/bin/wkhtmltopdf &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;chmod&lt;/span&gt; +x /opt/bin/wkhtmltopdf

&lt;span class="c"&gt;# Add app files&lt;/span&gt;
COPY &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LAMBDA_TASK_ROOT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Set the command for Lambda runtime&lt;/span&gt;
CMD &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"lambda_function.lambda_handler"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. logger.py&lt;/strong&gt;&lt;br&gt;
Here, we initialize the logger module, making it reusable across all scripts in the directory. The &lt;code&gt;get_logger&lt;/code&gt; function sets up basic logging with a log level of &lt;code&gt;INFO&lt;/code&gt;, and specifies a log format that includes the timestamp, logger name, log level, and the message. This logger is then returned and can be used in other scripts to maintain consistent logging throughout the project..&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import logging

def get_logger&lt;span class="o"&gt;()&lt;/span&gt;:
    logging.basicConfig&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;logging.INFO,  &lt;span class="c"&gt;# Set the minimum log level (DEBUG, INFO, WARNING, etc.)&lt;/span&gt;
        &lt;span class="nv"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"%(asctime)s - %(name)s - %(levelname)s - %(message)s"&lt;/span&gt;,  &lt;span class="c"&gt;# Log format&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;

    logger &lt;span class="o"&gt;=&lt;/span&gt; logging.getLogger&lt;span class="o"&gt;(&lt;/span&gt;__name__&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;logger
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. pdf_generator.py&lt;/strong&gt;&lt;br&gt;
This script will handle the generation of PDFs using the pdfkit library, which works in conjunction with the wkhtmltopdf binary to render HTML templates into PDFs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import pdfkit
import os
import jinja2
from logger import get_logger

TEMPLATES_DIR &lt;span class="o"&gt;=&lt;/span&gt; os.path.join&lt;span class="o"&gt;(&lt;/span&gt;os.path.dirname&lt;span class="o"&gt;(&lt;/span&gt;__file__&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="s2"&gt;"templates"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
PATH_WKHTMLTOPDF &lt;span class="o"&gt;=&lt;/span&gt; os.getenv&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"PATH_WKHTMLTOPDF"&lt;/span&gt;, &lt;span class="s2"&gt;"/opt/bin/wkhtmltopdf"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
KITOPTIONS &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"enable-local-file-access"&lt;/span&gt;: None,
    &lt;span class="s2"&gt;"disable-smart-shrinking"&lt;/span&gt;: &lt;span class="s2"&gt;""&lt;/span&gt;,
    &lt;span class="s2"&gt;"page-width"&lt;/span&gt;: &lt;span class="s2"&gt;"157mm"&lt;/span&gt;,
    &lt;span class="s2"&gt;"page-height"&lt;/span&gt;: &lt;span class="s2"&gt;"222.77mm"&lt;/span&gt;,
    &lt;span class="s2"&gt;"dpi"&lt;/span&gt;: 400,
    &lt;span class="s2"&gt;"encoding"&lt;/span&gt;: &lt;span class="s2"&gt;"UTF-8"&lt;/span&gt;,
    &lt;span class="s2"&gt;"margin-top"&lt;/span&gt;: &lt;span class="s2"&gt;"0cm"&lt;/span&gt;,
    &lt;span class="s2"&gt;"margin-right"&lt;/span&gt;: &lt;span class="s2"&gt;"0cm"&lt;/span&gt;,
    &lt;span class="s2"&gt;"margin-bottom"&lt;/span&gt;: &lt;span class="s2"&gt;"0cm"&lt;/span&gt;,
    &lt;span class="s2"&gt;"margin-left"&lt;/span&gt;: &lt;span class="s2"&gt;"0cm"&lt;/span&gt;,
    &lt;span class="s2"&gt;"custom-header"&lt;/span&gt;: &lt;span class="o"&gt;[(&lt;/span&gt;&lt;span class="s2"&gt;"Accept-Encoding"&lt;/span&gt;, &lt;span class="s2"&gt;"gzip"&lt;/span&gt;&lt;span class="o"&gt;)]&lt;/span&gt;,
    &lt;span class="s2"&gt;"no-outline"&lt;/span&gt;: None,
&lt;span class="o"&gt;}&lt;/span&gt;
TEMPLATE &lt;span class="o"&gt;=&lt;/span&gt; os.path.join&lt;span class="o"&gt;(&lt;/span&gt;TEMPLATES_DIR, &lt;span class="s2"&gt;"test.html"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

logger &lt;span class="o"&gt;=&lt;/span&gt; get_logger&lt;span class="o"&gt;()&lt;/span&gt;


def handle_pdf_generation&lt;span class="o"&gt;(&lt;/span&gt;body&lt;span class="o"&gt;)&lt;/span&gt;:
    &lt;span class="s2"&gt;"""
    Handle PDF generation

    :param body: dict

    :return: binary_pdf
    """&lt;/span&gt;

    try:
        logger.info&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Starting PDF generation"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# Ensure templates directory exists&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;not os.path.exists&lt;span class="o"&gt;(&lt;/span&gt;TEMPLATES_DIR&lt;span class="o"&gt;)&lt;/span&gt;:
            raise Exception&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Templates directory not found at {TEMPLATES_DIR}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# Ensure template file exists&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;not os.path.exists&lt;span class="o"&gt;(&lt;/span&gt;TEMPLATE&lt;span class="o"&gt;)&lt;/span&gt;:
            raise Exception&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Template file {TEMPLATE} not found"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# Load and render template&lt;/span&gt;
        template &lt;span class="o"&gt;=&lt;/span&gt; jinja2.Template&lt;span class="o"&gt;(&lt;/span&gt;open&lt;span class="o"&gt;(&lt;/span&gt;TEMPLATE&lt;span class="o"&gt;)&lt;/span&gt;.read&lt;span class="o"&gt;())&lt;/span&gt;
        rendered_template &lt;span class="o"&gt;=&lt;/span&gt; template.render&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;body&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# Configure pdfkit&lt;/span&gt;
        configuration &lt;span class="o"&gt;=&lt;/span&gt; pdfkit.configuration&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;wkhtmltopdf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PATH_WKHTMLTOPDF&lt;span class="o"&gt;)&lt;/span&gt;

        logger.info&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Generating PDF"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        pdf_file &lt;span class="o"&gt;=&lt;/span&gt; pdfkit.from_string&lt;span class="o"&gt;(&lt;/span&gt;
            rendered_template,
            &lt;span class="nv"&gt;output_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;False,
            &lt;span class="nv"&gt;options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;KITOPTIONS,
            &lt;span class="nv"&gt;configuration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;configuration,
        &lt;span class="o"&gt;)&lt;/span&gt;

        logger.info&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"PDF generated successfully"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;pdf_file
    except OSError as e:
        logger.error&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Error with wkhtmltopdf binary: {e}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        raise Exception&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Error with wkhtmltopdf binary: {e}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    except Exception as e:
        logger.error&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Error generating PDF: {e}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        raise Exception&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Error generating PDF: {e}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. lambda_function.py&lt;/strong&gt;&lt;br&gt;
This file will contain the logic for generating PDFs and uploading them to S3. We will use the &lt;code&gt;handle_pdf_generation&lt;/code&gt; function to generate a PDF and &lt;code&gt;upload_pdf&lt;/code&gt; to upload it to a local S3 bucket (using LocalStack).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import json
import random
from pdf_generator import handle_pdf_generation
from upload_file import upload_pdf
from logger import get_logger


logger &lt;span class="o"&gt;=&lt;/span&gt; get_logger&lt;span class="o"&gt;()&lt;/span&gt;


def lambda_handler&lt;span class="o"&gt;(&lt;/span&gt;event, context&lt;span class="o"&gt;)&lt;/span&gt;:
    logger.info&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Received event: {event}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    try:
        body &lt;span class="o"&gt;=&lt;/span&gt; event.get&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"body"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;not body:
            raise Exception&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"No body found in the request"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        logger.info&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Received body: {body}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# If body is a string, load it as JSON&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;isinstance&lt;span class="o"&gt;(&lt;/span&gt;body, str&lt;span class="o"&gt;)&lt;/span&gt;:
            body &lt;span class="o"&gt;=&lt;/span&gt; json.loads&lt;span class="o"&gt;(&lt;/span&gt;body&lt;span class="o"&gt;)&lt;/span&gt;

        logger.info&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Generating PDF"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        pdf_result_data &lt;span class="o"&gt;=&lt;/span&gt; handle_pdf_generation&lt;span class="o"&gt;(&lt;/span&gt;body&lt;span class="o"&gt;)&lt;/span&gt;

        file_name &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test_"&lt;/span&gt; + str&lt;span class="o"&gt;(&lt;/span&gt;random.randint&lt;span class="o"&gt;(&lt;/span&gt;1, 1000&lt;span class="o"&gt;))&lt;/span&gt; + &lt;span class="s2"&gt;".pdf"&lt;/span&gt;

        logger.info&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Uploading PDF to S3 with file name: {file_name}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        upload_pdf&lt;span class="o"&gt;(&lt;/span&gt;pdf_result_data, file_name&lt;span class="o"&gt;)&lt;/span&gt;
        logger.info&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"PDF uploaded successfully to S3 as {file_name}!"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"statusCode"&lt;/span&gt;: 200,
            &lt;span class="s2"&gt;"body"&lt;/span&gt;: json.dumps&lt;span class="o"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;"message"&lt;/span&gt;: &lt;span class="s2"&gt;"PDF generated and uploaded successfully!"&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt;,
        &lt;span class="o"&gt;}&lt;/span&gt;

    except Exception as e:
        logger.error&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Error: %s"&lt;/span&gt;, e, &lt;span class="nv"&gt;exc_info&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;True&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"statusCode"&lt;/span&gt;: 500,
            &lt;span class="s2"&gt;"body"&lt;/span&gt;: json.dumps&lt;span class="o"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;: f&lt;span class="s2"&gt;"Internal server error: {e}"&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt;,
        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. event.json&lt;/strong&gt;&lt;br&gt;
This file contains a sample event that will be used to test our Lambda function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"body"&lt;/span&gt; : &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"first_name"&lt;/span&gt;: &lt;span class="s2"&gt;"John"&lt;/span&gt;, &lt;span class="s2"&gt;"last_name"&lt;/span&gt;: &lt;span class="s2"&gt;"Doe"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7. templates/test.html&lt;/strong&gt;&lt;br&gt;
Create a &lt;code&gt;test.html&lt;/code&gt; file inside the templates directory within the &lt;code&gt;pdf-generator-lambda&lt;/code&gt; directory. This file will define a simple HTML structure that displays the &lt;code&gt;first_name&lt;/code&gt; and &lt;code&gt;last_name&lt;/code&gt; values passed to the Lambda function. The HTML will later be rendered and converted to a PDF.&lt;/p&gt;

&lt;p&gt;Here’s the code to include in &lt;code&gt;test.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;&lt;span class="o"&gt;!&lt;/span&gt;DOCTYPE html&amp;gt;
&amp;lt;html &lt;span class="nv"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"en"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &amp;lt;&lt;span class="nb"&gt;head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &amp;lt;meta &lt;span class="nv"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"UTF-8"&lt;/span&gt; /&amp;gt;
    &amp;lt;title&amp;gt;Test Page&amp;lt;/title&amp;gt;
    &amp;lt;&lt;span class="nb"&gt;link
      &lt;/span&gt;&lt;span class="nv"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://fonts.googleapis.com/css2?family=Poppins:wght@100;200;300;400;500;600;700&amp;amp;display=swap"&lt;/span&gt;
      &lt;span class="nv"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"stylesheet"&lt;/span&gt;
    /&amp;gt;
    &amp;lt;&lt;span class="nb"&gt;link
      &lt;/span&gt;&lt;span class="nv"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://api.fontshare.com/css?f[]=clash-display@400,700&amp;amp;display=swap"&lt;/span&gt;
      &lt;span class="nv"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"stylesheet"&lt;/span&gt;
    /&amp;gt;
    &amp;lt;&lt;span class="nb"&gt;link
      &lt;/span&gt;&lt;span class="nv"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400;500;700&amp;amp;display=swap"&lt;/span&gt;
      &lt;span class="nv"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"stylesheet"&lt;/span&gt;
    /&amp;gt;
    &amp;lt;style&amp;gt;
      body &lt;span class="o"&gt;{&lt;/span&gt;
        width: 595px&lt;span class="p"&gt;;&lt;/span&gt;
        margin: 0 auto&lt;span class="p"&gt;;&lt;/span&gt;
        font-family: &lt;span class="s2"&gt;"Poppins"&lt;/span&gt;, sans-serif&lt;span class="p"&gt;;&lt;/span&gt;
        font-size: 14px&lt;span class="p"&gt;;&lt;/span&gt;
        line-height: 1.6&lt;span class="p"&gt;;&lt;/span&gt;
        color: &lt;span class="c"&gt;#333;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      main &lt;span class="o"&gt;{&lt;/span&gt;
        width: 100%&lt;span class="p"&gt;;&lt;/span&gt;
        height: 100%&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      a &lt;span class="o"&gt;{&lt;/span&gt;
        color: &lt;span class="c"&gt;#26639b;&lt;/span&gt;
        text-decoration: none&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      h1 &lt;span class="o"&gt;{&lt;/span&gt;
        font-size: 28px&lt;span class="p"&gt;;&lt;/span&gt;
        font-weight: 600&lt;span class="p"&gt;;&lt;/span&gt;
        color: &lt;span class="c"&gt;#166082;&lt;/span&gt;
        margin-bottom: 20px&lt;span class="p"&gt;;&lt;/span&gt;
        text-align: center&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      .page-content &lt;span class="o"&gt;{&lt;/span&gt;
        width: 100%&lt;span class="p"&gt;;&lt;/span&gt;
        height: 100%&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      .label &lt;span class="o"&gt;{&lt;/span&gt;
        font-weight: 600&lt;span class="p"&gt;;&lt;/span&gt;
        color: &lt;span class="c"&gt;#166082;&lt;/span&gt;
        font-size: 14px&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      .value &lt;span class="o"&gt;{&lt;/span&gt;
        font-size: 14px&lt;span class="p"&gt;;&lt;/span&gt;
        white-space: pre-line&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      .detail &lt;span class="o"&gt;{&lt;/span&gt;
        margin-bottom: 15px&lt;span class="p"&gt;;&lt;/span&gt;
        padding-left: 55px&lt;span class="p"&gt;;&lt;/span&gt;
        padding-right: 55px&lt;span class="p"&gt;;&lt;/span&gt;
        padding-top: 5px&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      .footer &lt;span class="o"&gt;{&lt;/span&gt;
        margin-top: 20px&lt;span class="p"&gt;;&lt;/span&gt;
        text-align: center&lt;span class="p"&gt;;&lt;/span&gt;
        font-size: 12px&lt;span class="p"&gt;;&lt;/span&gt;
        color: &lt;span class="c"&gt;#888;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;main&amp;gt;
      &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"page-content"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &amp;lt;h1&amp;gt;PDF GENERATOR&amp;lt;/h1&amp;gt;
        &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"detail"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &amp;lt;span &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"label"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;First Name:&amp;lt;/span&amp;gt;
          &amp;lt;span &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"value"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;- &lt;span class="o"&gt;{{&lt;/span&gt;data.first_name&lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/span&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"detail"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &amp;lt;span &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"label"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;Last Name:&amp;lt;/span&amp;gt;
          &amp;lt;span &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"value"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;- &lt;span class="o"&gt;{{&lt;/span&gt;data.last_name&lt;span class="o"&gt;}}&lt;/span&gt;&amp;lt;/span&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/main&amp;gt;
    &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"footer"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &amp;lt;p&amp;gt;Generated by PDF Generator&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;8. upload_file.py&lt;/strong&gt;&lt;br&gt;
This script handles uploading a generated PDF to an S3 bucket. It sets up a boto3 S3 client with mock AWS credentials and a LocalStack endpoint, specifically using the &lt;code&gt;http://host.docker.internal:4566&lt;/code&gt; URL to ensure communication between the Docker container and LocalStack. The &lt;code&gt;upload_pdf&lt;/code&gt; function takes the PDF in byte format, wraps it in a BytesIO object, and calls the &lt;code&gt;upload_to_s3&lt;/code&gt; function, which handles the file upload.&lt;/p&gt;

&lt;p&gt;The script now checks if the S3 bucket (my-pdf-bucket) exists before attempting the upload. If the bucket does not exist, an error message is logged, and an exception is raised. This ensures that the upload only occurs if the bucket is present. The &lt;code&gt;check_bucket_exists&lt;/code&gt; function checks for the bucket's existence by calling the head_bucket operation. If the bucket is not found, the error is caught, and the appropriate message is logged.&lt;/p&gt;

&lt;p&gt;If the &lt;code&gt;S3_BUCKET_NAME&lt;/code&gt; environment variable is not set or is invalid, the script will log an error and raise an exception before attempting to upload the file, ensuring that the upload operation doesn't proceed without a valid bucket name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import boto3
from logger import get_logger
from io import BytesIO
from botocore.exceptions import ClientError

logger &lt;span class="o"&gt;=&lt;/span&gt; get_logger&lt;span class="o"&gt;()&lt;/span&gt;

AWS_ACCESS_KEY_ID &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
AWS_SECRET_ACCESS_KEY &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
S3_BUCKET_NAME &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-pdf-bucket"&lt;/span&gt;
BUCKET_REGION &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eu-west-1"&lt;/span&gt;
LOCALSTACK_HOST &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"http://host.docker.internal:4566"&lt;/span&gt;  &lt;span class="c"&gt;# Default LocalStack endpoint&lt;/span&gt;


def upload_to_s3&lt;span class="o"&gt;(&lt;/span&gt;file_bytes, filename, mimetype, &lt;span class="nv"&gt;object_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;None&lt;span class="o"&gt;)&lt;/span&gt;:
    &lt;span class="s2"&gt;"""
    Uploads a file to an S3 bucket

    :param file_bytes: Bytes object of the file to be uploaded
    :param filename: Name of the file
    :param mimetype: MIME type of the file
    :param object_name: Name of the object in the bucket

    :return: True if the file was uploaded, else False
    """&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;object_name is None:
        object_name &lt;span class="o"&gt;=&lt;/span&gt; filename

    try:
        s3_client &lt;span class="o"&gt;=&lt;/span&gt; create_S3_client&lt;span class="o"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;not check_bucket_exists&lt;span class="o"&gt;(&lt;/span&gt;s3_client, S3_BUCKET_NAME&lt;span class="o"&gt;)&lt;/span&gt;:
            logger.error&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Bucket {S3_BUCKET_NAME} does not exist."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            raise Exception&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Bucket {S3_BUCKET_NAME} does not exist."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# Wrap the bytes object in a BytesIO object&lt;/span&gt;
        file_obj &lt;span class="o"&gt;=&lt;/span&gt; BytesIO&lt;span class="o"&gt;(&lt;/span&gt;file_bytes&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# Upload the file object to S3 bucket&lt;/span&gt;
        s3_client.upload_fileobj&lt;span class="o"&gt;(&lt;/span&gt;
            file_obj, S3_BUCKET_NAME, object_name, &lt;span class="nv"&gt;ExtraArgs&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;&lt;span class="s2"&gt;"ContentType"&lt;/span&gt;: mimetype&lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;)&lt;/span&gt;

        logger.info&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"{object_name} uploaded to {S3_BUCKET_NAME} bucket"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    except ClientError as e:
        logger.error&lt;span class="o"&gt;(&lt;/span&gt;e&lt;span class="o"&gt;)&lt;/span&gt;
        raise Exception&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Error uploading file: {e}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    except Exception as e:
        logger.error&lt;span class="o"&gt;(&lt;/span&gt;e&lt;span class="o"&gt;)&lt;/span&gt;
        raise Exception&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Error uploading file: {e}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;


def create_S3_client&lt;span class="o"&gt;()&lt;/span&gt;:
    &lt;span class="s2"&gt;"""Create an S3 client."""&lt;/span&gt;

    s3_client &lt;span class="o"&gt;=&lt;/span&gt; boto3.client&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;"s3"&lt;/span&gt;,
        &lt;span class="nv"&gt;aws_access_key_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AWS_ACCESS_KEY_ID,
        &lt;span class="nv"&gt;aws_secret_access_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AWS_SECRET_ACCESS_KEY,
        &lt;span class="nv"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;BUCKET_REGION,
        &lt;span class="nv"&gt;endpoint_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;LOCALSTACK_HOST,  &lt;span class="c"&gt;# Point to LocalStack endpoint&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;s3_client

def check_bucket_exists&lt;span class="o"&gt;(&lt;/span&gt;s3_client, bucket_name&lt;span class="o"&gt;)&lt;/span&gt;:
    &lt;span class="s2"&gt;"""Check if the S3 bucket exists."""&lt;/span&gt;
    try:
        s3_client.head_bucket&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bucket_name&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;True  &lt;span class="c"&gt;# Bucket exists&lt;/span&gt;
    except ClientError as e:
        &lt;span class="c"&gt;# If the error is a 404, the bucket doesn't exist&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;e.response[&lt;span class="s2"&gt;"Error"&lt;/span&gt;&lt;span class="o"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;"Code"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"404"&lt;/span&gt;:
            &lt;span class="k"&gt;return &lt;/span&gt;False
        &lt;span class="k"&gt;else&lt;/span&gt;:
            &lt;span class="c"&gt;# Other errors, log and re-raise&lt;/span&gt;
            logger.error&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Error checking if bucket exists: {e}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            raise

def upload_pdf&lt;span class="o"&gt;(&lt;/span&gt;file_bytes, filename&lt;span class="o"&gt;)&lt;/span&gt;:
    &lt;span class="c"&gt;# Check if the S3 bucket name is valid&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;not S3_BUCKET_NAME:
        logger.error&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"S3_BUCKET_NAME is not set properly. The file cannot be uploaded."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        raise Exception&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s2"&gt;"Invalid S3_BUCKET_NAME environment variable. File upload failed."&lt;/span&gt;
        &lt;span class="o"&gt;)&lt;/span&gt;
    try:
        upload_to_s3&lt;span class="o"&gt;(&lt;/span&gt;file_bytes, filename, &lt;span class="s2"&gt;"application/pdf"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        logger.info&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"File uploaded successfully!"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    except Exception as e:
        logger.error&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Error: {e}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        raise Exception&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"Error uploading file: {e}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Now that we've covered all the files and code required, let's move on to setting up the services.&lt;/em&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  SERVICES SETUP AND TESTING
&lt;/h2&gt;

&lt;p&gt;Before proceeding, ensure that your LocalStack container is up and running. If it isn’t already running, export your &lt;code&gt;LOCALSTACK_AUTH_TOKEN&lt;/code&gt; and start a new container using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DEBUG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 localstack start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;S3 Bucket&lt;/strong&gt;&lt;br&gt;
First, let's create the S3 bucket where we'll store the generated PDFs. Run the following command to create a bucket named &lt;code&gt;my-pdf-bucket&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;awslocal s3 mb s3://my-pdf-bucket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then verify the bucket creation via the CLI using &lt;code&gt;awslocal s3 ls&lt;/code&gt; or by checking your LocalStack Desktop application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Elastic Container Registry (ECR)&lt;/strong&gt;&lt;br&gt;
Now, let's create a repository in the Elastic Container Registry (ECR) to store the Docker image for the function. Run the command below to create a new repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;awslocal ecr create-repository &lt;span class="nt"&gt;--repository-name&lt;/span&gt; pdf-generator-image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see a response similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"repository"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"repositoryArn"&lt;/span&gt;: &lt;span class="s2"&gt;"arn:aws:ecr:eu-west-1:000000000000:repository/pdf-generator-image"&lt;/span&gt;,
        &lt;span class="s2"&gt;"registryId"&lt;/span&gt;: &lt;span class="s2"&gt;"000000000000"&lt;/span&gt;,
        &lt;span class="s2"&gt;"repositoryName"&lt;/span&gt;: &lt;span class="s2"&gt;"pdf-generator-imager"&lt;/span&gt;,
        &lt;span class="s2"&gt;"repositoryUri"&lt;/span&gt;: &lt;span class="s2"&gt;"000000000000.dkr.ecr.eu-west-1.localhost.localstack.cloud:4566/pdf-generator-image"&lt;/span&gt;,
        &lt;span class="s2"&gt;"createdAt"&lt;/span&gt;: 1736994302.0,
        &lt;span class="s2"&gt;"imageTagMutability"&lt;/span&gt;: &lt;span class="s2"&gt;"MUTABLE"&lt;/span&gt;,
        &lt;span class="s2"&gt;"imageScanningConfiguration"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"scanOnPush"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="s2"&gt;"encryptionConfiguration"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"encryptionType"&lt;/span&gt;: &lt;span class="s2"&gt;"AES256"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please note down your &lt;code&gt;repositoryUri&lt;/code&gt; as we'll need it in subsequent steps. If you clear your terminal after creating the repository, you can also easily retrieve these details later by running this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;awslocal ecr describe-repositories
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Docker Image&lt;/strong&gt;&lt;br&gt;
Now let’s time to build our Docker image, tag it with the &lt;code&gt;repositoryUri&lt;/code&gt; from earlier, and push it to the Elastic Container Registry (ECR).&lt;/p&gt;

&lt;p&gt;First, run the following command to build the Docker image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;--no-cache&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; lambda-container-image &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the build is complete, tag the image with your repository URI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker tag lambda-container-image 000000000000.dkr.ecr.eu-west-1.localhost.localstack.cloud:4566/pdf-generator-image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: Replace the &lt;code&gt;repositoryUri&lt;/code&gt; in the command above with your own URI if it's different from the one provided in this example.&lt;/p&gt;

&lt;p&gt;Finally, push the tagged image to ECR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker push 000000000000.dkr.ecr.eu-west-1.localhost.localstack.cloud:4566/pdf-generator-image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: Be sure to use the correct &lt;code&gt;repositoryUri&lt;/code&gt; when tagging and pushing the image. Using the wrong &lt;code&gt;repositoryUri&lt;/code&gt; or &lt;code&gt;tagId&lt;/code&gt; will result in errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lambda Function&lt;/strong&gt;&lt;br&gt;
Next, let's create the Lambda function using the image we uploaded to the Elastic Container Registry. &lt;/p&gt;

&lt;p&gt;Run the following command to create the Lambda function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;awslocal lambda create-function &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--function-name&lt;/span&gt; pdf-generator-lambda &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--package-type&lt;/span&gt; Image &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--code&lt;/span&gt; &lt;span class="nv"&gt;ImageUri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"000000000000.dkr.ecr.eu-west-1.localhost.localstack.cloud:4566/pdf-generator-image"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--role&lt;/span&gt; arn:aws:iam::000000000000:role/lambda-role &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--handler&lt;/span&gt; lambda_function.lambda_handler &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--timeout&lt;/span&gt; 60 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--architectures&lt;/span&gt; arm64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We set the Lambda function name to &lt;code&gt;pdf-generator-lambda&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ImageUri&lt;/code&gt; refers to the &lt;code&gt;repositoryUri&lt;/code&gt; of the image we uploaded earlier to ECR.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;handler&lt;/code&gt; specifies the entry point of the Lambda function. In this case, it's the &lt;code&gt;lambda_handler&lt;/code&gt; function in the &lt;code&gt;lambda_function.py&lt;/code&gt; file, which runs our entire process.&lt;/li&gt;
&lt;li&gt;We set the &lt;code&gt;timeout&lt;/code&gt; to 60 seconds to allow sufficient time for both PDF generation and the upload process. You can adjust this based on your system and the expected size of the PDF. Larger PDFs will take more time to generate and upload.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;architectures&lt;/code&gt; parameter is set to &lt;code&gt;arm64&lt;/code&gt; to match the architecture of my local processor. If you're using a machine with an &lt;code&gt;x86_64&lt;/code&gt; architecture, you should update this accordingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a quick sanity check, run the following command to confirm that your Lambda function has been created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;awslocal lambda list-functions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will list all Lambda functions deployed in your LocalStack environment. If successful, you should see your pdf-generator-lambda function in the output.&lt;/p&gt;

&lt;p&gt;Finally, let's invoke our Lambda function to validate everything we've done. Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;awslocal lambda invoke &lt;span class="nt"&gt;--function-name&lt;/span&gt; pdf-generator-lambda &lt;span class="nt"&gt;--payload&lt;/span&gt; file://event.json /tmp/lambda.out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--function-name&lt;/code&gt; specifies the name of the Lambda function to invoke, which is pdf-generator-lambda in this case.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--payload&lt;/code&gt; passes an input event to the function, simulating a real-world invocation. Here, the payload is sourced from the &lt;code&gt;event.json&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/tmp/lambda.out&lt;/code&gt; is the output file path where the logs generated by the Lambda function during execution will be stored.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After running the command, you should see the following response in your terminal, indicating that the Lambda function executed successfully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"StatusCode"&lt;/span&gt;: 200,
    &lt;span class="s2"&gt;"ExecutedVersion"&lt;/span&gt;: &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LATEST&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To confirm that the function executed successfully, I'll be using the LocalStack Desktop application, as it simplifies downloading the generated PDF file from the S3 bucket. Navigate to the S3 resource in the resource list within your active container in the LocalStack Desktop interface. You should see your PDF file listed there. Click on it, and you’ll be prompted to download the file. Download the file and verify that it contains the expected content similar to the screenshot below. &lt;/p&gt;

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

&lt;p&gt;If you can see the generated PDF, that means we have successfully created a Lambda function locally, built it as a Docker image, created an Elastic Container Registry, uploaded the image to it, set up an S3 bucket, invoked our Lambda function, and successfully generated a PDF that was stored in the S3 bucket. And the best part? We accomplished all of this without needing an actual AWS account. Pretty impressive, right?&lt;/p&gt;

&lt;p&gt;Now, if you need to make changes to your Lambda function, you’ll have to repeat the process: rebuild the image, retag it, push it to the ECR, and then update the Lambda function with the new image. To update your Lambda function, you can use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;awslocal lambda update-function-code &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--function-name&lt;/span&gt; pdf-generator-lambda &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--image-uri&lt;/span&gt; &lt;span class="s2"&gt;"000000000000.dkr.ecr.eu-west-1.localhost.localstack.cloud:4566/pdf-generator-image"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Congratulations! 🎉&lt;/strong&gt;&lt;br&gt;
You’ve reached the end of this article—thank you for reading! 😊 I hope to extend this series with more articles, so stay tuned.&lt;/p&gt;

&lt;p&gt;If you have any questions, feel free to leave a comment or send me a message on &lt;a href="https://www.linkedin.com/in/faruq-abdulsalam/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;. I’ll make sure to respond as quickly as I can. Ciao 👋&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>cloud</category>
      <category>aws</category>
      <category>docker</category>
    </item>
    <item>
      <title>How to Simulate AWS S3 on Your Local Machine with LocalStack</title>
      <dc:creator>Faruq Abdulsalam</dc:creator>
      <pubDate>Wed, 08 Jan 2025 09:43:29 +0000</pubDate>
      <link>https://dev.to/nagatodev/how-to-simulate-aws-s3-on-your-local-machine-with-localstack-53dl</link>
      <guid>https://dev.to/nagatodev/how-to-simulate-aws-s3-on-your-local-machine-with-localstack-53dl</guid>
      <description>&lt;p&gt;In this article, I’ll walk you through the process of simulating an AWS S3 bucket in your local environment — no AWS account required. By the end, you’ll know how to create S3 buckets locally, upload files to them, and download the uploaded files with ease.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/get-started/get-docker/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.python.org/downloads/" rel="noopener noreferrer"&gt;Python 3.9+&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  LocalStack Setup
&lt;/h2&gt;

&lt;p&gt;First, set up your LocalStack environment. If you’ve already done this, feel free to skip this section&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LocalStack CLI&lt;/strong&gt;&lt;br&gt;
The first step is to install the LocalStack CLI(Command Line Interface). This &lt;a href="https://docs.localstack.cloud/getting-started/installation/" rel="noopener noreferrer"&gt;link&lt;/a&gt; contains an easy guide on how to install the CLI depending on the OS of your machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LocalStack account&lt;/strong&gt;&lt;br&gt;
After successfully installing the CLI, create a LocalStack account &lt;a href="https://app.localstack.cloud/sign-up?__hstc=108988063.d47cb3a4e01c0660105f507c72bbb5a0.1734466298921.1736212471122.1736242985972.7&amp;amp;__hssc=108988063.2.1736242985972&amp;amp;__hsfp=3343512732" rel="noopener noreferrer"&gt;here&lt;/a&gt;. This will give you access to your own dashboard, where you can manage your account, retrieve your auth token, manage subscriptions, monitor stack insights, and explore other features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You don't have to actually pay for any subscription if you are not using LocalStack for commercial purposes. LocalStack offers a Hobby Subscription for enthusiasts like myself. If you're not building for commercial purposes, you can select this option through the Subscriptions page in your dashboard. This will give you access to a wide range of open source as well as pro services and features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LocalStack Desktop&lt;/strong&gt;&lt;br&gt;
Next I highly recommend you install the &lt;a href="https://docs.localstack.cloud/user-guide/tools/localstack-desktop/" rel="noopener noreferrer"&gt;LocalStack Desktop&lt;/a&gt; application. This will be give you a visual display of your created services, logs, uploaded files e.t.c. This will be really helpful for conducting sanity checks. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LocalStack Authentication Token&lt;/strong&gt;&lt;br&gt;
You can find your authentication token on the &lt;code&gt;Auth Tokens&lt;/code&gt; page of your dashboard. Make sure to set this variable before starting LocalStack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;LOCALSTACK_AUTH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-auth-token"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Configure your environment&lt;/strong&gt;&lt;br&gt;
Next, set the environment variables in your shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_DEFAULT_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"eu-west-1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your region is different (e.g., eu-central-1, us-east-1, etc.), be sure to update the AWS_DEFAULT_REGION to match.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The variables set using this approach will only persist for the duration of the current shell session and will be cleared when the session ends. If you want to avoid repeating this process every time, you can configure a custom profile to use with LocalStack.&lt;/p&gt;

&lt;p&gt;With everything in place, you're good to go! For a quick sanity check, make sure Docker is running on your machine (either using the CLI or Docker Desktop), and then run the following command in your shell to ensure everything is configured correctly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DEBUG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 localstack start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The DEBUG=1 command enables debug-level logging for LocalStack, allowing you to easily monitor and troubleshoot what's happening behind the scenes. While you'll see a lot of verbose information during startup, don't worry about it. Simply scroll to the bottom of the logs and look for this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Ready.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see this message, it means LocalStack has started successfully. Now, open the LocalStack Desktop application, and you should see the new container in the list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local Environment Setup
&lt;/h2&gt;

&lt;p&gt;Follow the following steps to properly set up your local environment.&lt;br&gt;
&lt;strong&gt;1. Create a new directory:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;localstack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Move into the new directory:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;localstack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Create a virtual environment:&lt;/strong&gt;&lt;br&gt;
It’s recommended to create a virtual environment to avoid installing dependencies globally, which might conflict with dependencies for other projects on your machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;For mac/unix &lt;span class="nb"&gt;users&lt;/span&gt;: 
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv &lt;span class="nb"&gt;env
&lt;/span&gt;For windows &lt;span class="nb"&gt;users&lt;/span&gt;: 
py &lt;span class="nt"&gt;-m&lt;/span&gt; venv &lt;span class="nb"&gt;env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating the environment, activate it by running :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;For mac/unix &lt;span class="nb"&gt;users&lt;/span&gt;: 
&lt;span class="nb"&gt;source env&lt;/span&gt;/bin/activate
For windows &lt;span class="nb"&gt;users&lt;/span&gt;: 
.&lt;span class="se"&gt;\e&lt;/span&gt;nv&lt;span class="se"&gt;\S&lt;/span&gt;cripts&lt;span class="se"&gt;\a&lt;/span&gt;ctivate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Install Boto3 for S3:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This will install the boto3 library, which is the AWS SDK for Python. You will use it to interact with S3, and other AWS services, locally simulated by LocalStack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Install the LocalStack AWS CLI(awslocal):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s1"&gt;'awscli-local[ver1]'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will install AWS CLI v1 in your new environment. Using a virtual environment ensures there’s no clash with an existing AWS CLI v2 installation (if you already have it installed, which is likely). The LocalStack documentation mentions certain limitations with AWS CLI v2, so sticking with v1 is recommended for this setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.Verify the installation:&lt;/strong&gt;&lt;br&gt;
You can verify that the installation was succesful by running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="c"&gt;# OR&lt;/span&gt;
awslocal &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see something similar to this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws-cli/1.36.34 Python/3.9.6 Darwin/24.1.0 botocore/1.35.93
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your output is similar, you're on the right track—let’s move on!&lt;/p&gt;

&lt;h2&gt;
  
  
  Create an S3 bucket in the LocalStack container
&lt;/h2&gt;

&lt;p&gt;Even though we’re using LocalStack, remember that it’s designed to completely mock AWS services. This means we’ll still use AWS CLI commands to interact with our services.&lt;/p&gt;

&lt;p&gt;The key difference is that instead of using the aws command, we’ll use the awslocal command. The reason for this is that awslocal is a thin wrapper around aws—it automatically appends the endpoint URL (your LocalStack URL) to every command you run.&lt;/p&gt;

&lt;p&gt;If you decide to use the aws prefix instead, you’ll need to either configure the endpoint URL in your AWS profile or append it manually to every command. This approach is tedious and unnecessary, so I strongly recommend sticking with awslocal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create Bucket&lt;/strong&gt;&lt;br&gt;
Run the command below to create an S3 bucket with the name &lt;code&gt;my-new-bucket&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;awslocal s3 mb s3://my-new-bucket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the following response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make_bucket: my-new-bucket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Verify the Bucket Creation via the CLI&lt;/strong&gt;&lt;br&gt;
To ensure the bucket has been created, list all available buckets using this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;awslocal s3 &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response should display the date, time, and name of the bucket, confirming its creation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verify Using LocalStack Desktop&lt;/strong&gt;&lt;br&gt;
For a visual confirmation, you can use LocalStack Desktop. After all, seeing is believing! 😊&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the LocalStack Desktop application.&lt;/li&gt;
&lt;li&gt;Look for your active container in the container list.&lt;/li&gt;
&lt;li&gt;Select the container&lt;/li&gt;
&lt;li&gt;At the top center of the application, you’ll see four buttons. Hover over the last button to reveal its name: Resource Browser.&lt;/li&gt;
&lt;li&gt;Click Resource Browser, and a list of supported AWS services will appear.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhqt4dqps73sasea20awy.png" alt="Screenshot of localstack desktop" width="800" height="530"&gt;
&lt;/li&gt;
&lt;li&gt;Locate S3 in the list and select it.&lt;/li&gt;
&lt;li&gt;Choose your region from the bottom-right corner of the screen.&lt;/li&gt;
&lt;li&gt;Refresh the view using the button at the top-right corner.
You should now see your created bucket listed.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1oslwpd7ewto8hnj0p2h.png" alt="Screenshot of s3 bucket list" width="800" height="282"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Congratulations! 🎉 You’ve just created an S3 bucket without needing an AWS account — pretty amazing, right? 😊&lt;/p&gt;
&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Now that your bucket is ready, let's test it by uploading a file to verify that it works as expected. We are going to create a simple python script to interact with out s3 bucket using the boto3 package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Create your script file in the same directory &lt;code&gt;localstack&lt;/code&gt; where your virtual environment was created:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;base.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Import required libraries:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import boto3
import logging
from io import BytesIO
from botocore.exceptions import ClientError
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Configure the &lt;code&gt;logger&lt;/code&gt; module:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;logging.basicConfig&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;logging.DEBUG,  &lt;span class="c"&gt;# Set the minimum log level (DEBUG, INFO, WARNING, etc.)&lt;/span&gt;
    &lt;span class="nv"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"%(asctime)s - %(name)s - %(levelname)s - %(message)s"&lt;/span&gt;,  &lt;span class="c"&gt;# Log format&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

logger &lt;span class="o"&gt;=&lt;/span&gt; logging.getLogger&lt;span class="o"&gt;(&lt;/span&gt;__name__&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Define Configuration Variables:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;AWS_ACCESS_KEY_ID &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
AWS_SECRET_ACCESS_KEY &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
S3_BUCKET_NAME &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-new-bucket"&lt;/span&gt;
LOCALSTACK_HOST &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"http://localhost:4566"&lt;/span&gt;  &lt;span class="c"&gt;# Default LocalStack endpoint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; and &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt; variables are needed to create the client with boto3 but their values are not really important in this situation so you can assign any random value to them. The value assigned to the &lt;code&gt;S3_BUCKET_NAME&lt;/code&gt; variable should be the actual name of the bucket you created above. If this is wrong, you'll get this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;botocore.errorfactory.NoSuchBucket: An error occurred (NoSuchBucket) when calling the PutObject operation: The specified bucket does not exist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, ensure the &lt;code&gt;LOCALSTACK_HOST&lt;/code&gt; variable is be set to your LocalStack endpoint url.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Create the S3 Client:&lt;/strong&gt;&lt;br&gt;
To run a sanity check, let's try to create a new boto3 client and use that to list out s3 buckets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;def create_S3_client&lt;span class="o"&gt;()&lt;/span&gt;:
    s3_client &lt;span class="o"&gt;=&lt;/span&gt; boto3.client&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;"s3"&lt;/span&gt;,
        &lt;span class="nv"&gt;aws_access_key_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AWS_ACCESS_KEY_ID,
        &lt;span class="nv"&gt;aws_secret_access_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AWS_SECRET_ACCESS_KEY,
        &lt;span class="nv"&gt;endpoint_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;LOCALSTACK_HOST,  &lt;span class="c"&gt;# Point to LocalStack endpoint&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;s3_client

def main&lt;span class="o"&gt;()&lt;/span&gt;:
    s3Client &lt;span class="o"&gt;=&lt;/span&gt; create_S3_client&lt;span class="o"&gt;()&lt;/span&gt;
    response &lt;span class="o"&gt;=&lt;/span&gt; s3Client.list_buckets&lt;span class="o"&gt;()&lt;/span&gt;
    print&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Buckets:"&lt;/span&gt;, response[&lt;span class="s2"&gt;"Buckets"&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;

main&lt;span class="o"&gt;()&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Run the script using &lt;code&gt;python3 base.py&lt;/code&gt;. Your response should contain a List of your created buckets, in this case it should contain only one item , an object with the &lt;code&gt;Name&lt;/code&gt; and &lt;code&gt;CreationDate&lt;/code&gt; of the bucket. now that we have validated this. Let's go ahead and finish up the python script.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Create the &lt;code&gt;upload&lt;/code&gt; method:&lt;/strong&gt;&lt;br&gt;
We will be uploading an image so please move any &lt;strong&gt;jpg&lt;/strong&gt; image of your choice into the &lt;code&gt;localstack&lt;/code&gt; directory where the &lt;code&gt;base.py&lt;/code&gt; file is also located. And change the name of the image to &lt;code&gt;file.jpg&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;def upload_to_s3&lt;span class="o"&gt;(&lt;/span&gt;file_bytes, filename, mimetype, &lt;span class="nv"&gt;object_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;None&lt;span class="o"&gt;)&lt;/span&gt;:
    &lt;span class="s2"&gt;"""
    Uploads a file to an S3 bucket

    :param file_bytes: Bytes object of the file to be uploaded
    :param filename: Name of the file
    :param mimetype: MIME type of the file
    :param object_name: Name of the object in the bucket

    :return: True if the file was uploaded, else False
    """&lt;/span&gt;

    s3_client &lt;span class="o"&gt;=&lt;/span&gt; create_S3_client&lt;span class="o"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;object_name is None:
        object_name &lt;span class="o"&gt;=&lt;/span&gt; filename

    try:
        &lt;span class="c"&gt;# Wrap the bytes object in a BytesIO object&lt;/span&gt;
        file_obj &lt;span class="o"&gt;=&lt;/span&gt; BytesIO&lt;span class="o"&gt;(&lt;/span&gt;file_bytes&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# Upload the file object to S3 bucket&lt;/span&gt;
        response &lt;span class="o"&gt;=&lt;/span&gt; s3_client.upload_fileobj&lt;span class="o"&gt;(&lt;/span&gt;
            file_obj, S3_BUCKET_NAME, object_name, &lt;span class="nv"&gt;ExtraArgs&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;&lt;span class="s2"&gt;"ContentType"&lt;/span&gt;: mimetype&lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;)&lt;/span&gt;
        logger.info&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"{object_name} uploaded to {S3_BUCKET_NAME} bucket"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        logger.info&lt;span class="o"&gt;(&lt;/span&gt;response&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;True
    except ClientError as e:
        logger.error&lt;span class="o"&gt;(&lt;/span&gt;e&lt;span class="o"&gt;)&lt;/span&gt;
        logger.exception&lt;span class="o"&gt;(&lt;/span&gt;e&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7. Read File Data:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;def read_file&lt;span class="o"&gt;()&lt;/span&gt;:
    file_bytes &lt;span class="o"&gt;=&lt;/span&gt; None
    filename &lt;span class="o"&gt;=&lt;/span&gt; None
    mimetype &lt;span class="o"&gt;=&lt;/span&gt; None
    with open&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"file.jpg"&lt;/span&gt;, &lt;span class="s2"&gt;"rb"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; as file:
        file_bytes &lt;span class="o"&gt;=&lt;/span&gt; file.read&lt;span class="o"&gt;()&lt;/span&gt;
        filename &lt;span class="o"&gt;=&lt;/span&gt; f&lt;span class="s2"&gt;"images/{file.name}"&lt;/span&gt;
        mimetype &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"image/jpeg"&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;file_bytes, filename, mimetype
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; By setting the file name like this above &lt;code&gt;f"images/{file.name}"&lt;/code&gt; means our file will be uploaded into the &lt;code&gt;images/&lt;/code&gt; directory in the s3 bucket and if it does not exist it will first be created.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Create the &lt;code&gt;main&lt;/code&gt; method&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;def main&lt;span class="o"&gt;()&lt;/span&gt;:
    file_bytes, filename, mimetype &lt;span class="o"&gt;=&lt;/span&gt; read_file&lt;span class="o"&gt;()&lt;/span&gt;

    status &lt;span class="o"&gt;=&lt;/span&gt; upload_to_s3&lt;span class="o"&gt;(&lt;/span&gt;file_bytes, filename, mimetype&lt;span class="o"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;status:
        logger.info&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"File uploaded successfully!"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;:
        logger.error&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"File upload failed."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;__name__ &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"__main__"&lt;/span&gt;:
    main&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final code should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import boto3
import logging
from io import BytesIO
from botocore.exceptions import ClientError

logging.basicConfig&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;logging.DEBUG,  &lt;span class="c"&gt;# Set the minimum log level (DEBUG, INFO, WARNING, etc.)&lt;/span&gt;
    &lt;span class="nv"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"%(asctime)s - %(name)s - %(levelname)s - %(message)s"&lt;/span&gt;,  &lt;span class="c"&gt;# Log format&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

logger &lt;span class="o"&gt;=&lt;/span&gt; logging.getLogger&lt;span class="o"&gt;(&lt;/span&gt;__name__&lt;span class="o"&gt;)&lt;/span&gt;

AWS_ACCESS_KEY_ID &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tester"&lt;/span&gt;
AWS_SECRET_ACCESS_KEY &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
S3_BUCKET_NAME &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-new-bucket"&lt;/span&gt;
LOCALSTACK_HOST &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"http://localhost:4566"&lt;/span&gt;  &lt;span class="c"&gt;# Default LocalStack endpoint&lt;/span&gt;


def upload_to_s3&lt;span class="o"&gt;(&lt;/span&gt;file_bytes, filename, mimetype, &lt;span class="nv"&gt;object_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;None&lt;span class="o"&gt;)&lt;/span&gt;:
    &lt;span class="s2"&gt;"""
    Uploads a file to an S3 bucket

    :param file_bytes: Bytes object of the file to be uploaded
    :param filename: Name of the file
    :param mimetype: MIME type of the file
    :param object_name: Name of the object in the bucket

    :return: True if the file was uploaded, else False
    """&lt;/span&gt;

    s3_client &lt;span class="o"&gt;=&lt;/span&gt; create_S3_client&lt;span class="o"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;object_name is None:
        object_name &lt;span class="o"&gt;=&lt;/span&gt; filename

    try:
        &lt;span class="c"&gt;# Wrap the bytes object in a BytesIO object&lt;/span&gt;
        file_obj &lt;span class="o"&gt;=&lt;/span&gt; BytesIO&lt;span class="o"&gt;(&lt;/span&gt;file_bytes&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;# Upload the file object to S3 bucket&lt;/span&gt;
        response &lt;span class="o"&gt;=&lt;/span&gt; s3_client.upload_fileobj&lt;span class="o"&gt;(&lt;/span&gt;
            file_obj, S3_BUCKET_NAME, object_name, &lt;span class="nv"&gt;ExtraArgs&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;&lt;span class="s2"&gt;"ContentType"&lt;/span&gt;: mimetype&lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;)&lt;/span&gt;
        logger.info&lt;span class="o"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;"{object_name} uploaded to {S3_BUCKET_NAME} bucket"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        logger.info&lt;span class="o"&gt;(&lt;/span&gt;response&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;True
    except ClientError as e:
        logger.error&lt;span class="o"&gt;(&lt;/span&gt;e&lt;span class="o"&gt;)&lt;/span&gt;
        logger.exception&lt;span class="o"&gt;(&lt;/span&gt;e&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;False


def create_S3_client&lt;span class="o"&gt;()&lt;/span&gt;:
    s3_client &lt;span class="o"&gt;=&lt;/span&gt; boto3.client&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;"s3"&lt;/span&gt;,
        &lt;span class="nv"&gt;aws_access_key_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AWS_ACCESS_KEY_ID,
        &lt;span class="nv"&gt;aws_secret_access_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AWS_SECRET_ACCESS_KEY,
        &lt;span class="nv"&gt;endpoint_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;LOCALSTACK_HOST,  &lt;span class="c"&gt;# Point to LocalStack endpoint&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;s3_client


def read_file&lt;span class="o"&gt;()&lt;/span&gt;:
    file_bytes &lt;span class="o"&gt;=&lt;/span&gt; None
    filename &lt;span class="o"&gt;=&lt;/span&gt; None
    mimetype &lt;span class="o"&gt;=&lt;/span&gt; None
    with open&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"file.jpg"&lt;/span&gt;, &lt;span class="s2"&gt;"rb"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; as file:
        file_bytes &lt;span class="o"&gt;=&lt;/span&gt; file.read&lt;span class="o"&gt;()&lt;/span&gt;
        filename &lt;span class="o"&gt;=&lt;/span&gt; f&lt;span class="s2"&gt;"images/{file.name}"&lt;/span&gt;
        mimetype &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"image/jpeg"&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;file_bytes, filename, mimetype


def main&lt;span class="o"&gt;()&lt;/span&gt;:
    file_bytes, filename, mimetype &lt;span class="o"&gt;=&lt;/span&gt; read_file&lt;span class="o"&gt;()&lt;/span&gt;

    status &lt;span class="o"&gt;=&lt;/span&gt; upload_to_s3&lt;span class="o"&gt;(&lt;/span&gt;file_bytes, filename, mimetype&lt;span class="o"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;status:
        logger.info&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"File uploaded successfully!"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;:
        logger.error&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"File upload failed."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if &lt;/span&gt;__name__ &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"__main__"&lt;/span&gt;:
    main&lt;span class="o"&gt;()&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;9. Run the script:&lt;/strong&gt;&lt;br&gt;
Run the script using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 base.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your file is uploaded successfully you should see this in your logs.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;10. Verify Upload:&lt;/strong&gt;&lt;br&gt;
Now that you’ve uploaded your file to the S3 bucket &lt;code&gt;my-new-bucket&lt;/code&gt;, let’s verify that the file exists.. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option1 - Verify via the CLI:&lt;/strong&gt;&lt;br&gt;
Run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;awslocal s3 &lt;span class="nb"&gt;ls &lt;/span&gt;s3://my-new-bucket/images/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will return a list of all files in the &lt;code&gt;images/&lt;/code&gt; directory of the &lt;code&gt;my-new-bucket&lt;/code&gt; bucket. You should see &lt;code&gt;file.jpg&lt;/code&gt; in the response, similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;2025-01-07 12:00:00       12345 file.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Option2 - Verify via LocalStack Desktop:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;LocalStack Desktop&lt;/code&gt; and navigate to the &lt;code&gt;S3 service&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Select the bucket &lt;code&gt;my-new-bucket&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Refresh the view, and you should see the &lt;code&gt;images/&lt;/code&gt; directory. Inside, you’ll find your &lt;code&gt;file.jpg&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;To double-check, click on the file row to download it to your local machine. Open the file to ensure it matches the original image you uploaded.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Congratulations! 🎉&lt;/strong&gt;&lt;br&gt;
You’ve successfully created an S3 bucket, uploaded a file, and verified its existence—all without needing an AWS account. I hope you’ve experienced your wow moments already! This guide demonstrates how simple, straightforward, and fast it is to work with AWS services on your local machine using LocalStack.&lt;/p&gt;

&lt;p&gt;With LocalStack, you can truly keep local development local, saving time and resources while ensuring a smoother development workflow.&lt;/p&gt;

&lt;p&gt;In the next part of this series, I’ll show you how to mock AWS Lambda functions locally using the LocalStack platform. Stay tuned — it’s going to be another exciting dive into the world of local AWS development! 😊&lt;/p&gt;

&lt;p&gt;If you have any questions, feel free to drop them as a comment or send me a message on &lt;a href="https://www.linkedin.com/in/faruq-abdulsalam/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and I'll ensure I respond as quickly as I can. Ciao 👋&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>cloud</category>
      <category>aws</category>
      <category>s3</category>
    </item>
    <item>
      <title>Simplifying Local AWS Development with LocalStack</title>
      <dc:creator>Faruq Abdulsalam</dc:creator>
      <pubDate>Tue, 07 Jan 2025 09:02:04 +0000</pubDate>
      <link>https://dev.to/nagatodev/local-development-with-aws-services-a-hands-on-journey-with-localstack-1jgl</link>
      <guid>https://dev.to/nagatodev/local-development-with-aws-services-a-hands-on-journey-with-localstack-1jgl</guid>
      <description>&lt;p&gt;So far in my career, I have developed several noteworthy full-stack applications utilizing AWS services, with the applications themselves hosted on AWS. Often, I’ve had to set up a local demo account on AWS to leverage several services in free-tier mode during development. These services include S3 for data storage, Cognito for authentication, API Gateway, AWS Lambda, Elastic Container Registry, Certificate Manager, Simple Email Service (SES), and Simple Notification Service (SNS), among many others. The list is endless.&lt;/p&gt;

&lt;p&gt;To test how the application would behave in a live environment, I’d also need to set up EC2 instances (app servers), CloudWatch for alarms and logs, and EventBridge for task scheduling. This made me question whether this can still be called "local development." After all, we’re relying on live AWS services, and we can’t fully validate how everything will work until it’s in the staging environment.&lt;/p&gt;

&lt;p&gt;On a recent project, we had several Lambda functions that needed to be validated before deployment. To make testing easier, we mocked the API Gateway using the FastAPI framework to invoke the Lambda functions. This approach allowed us to test each Lambda function during development. However, we ran into a frustrating bug (the infamous "But it works fine on my system" issue). The cause? Our local API Gateway environment had different settings from the cloud environment. I genuinely believe that if we had an option to mock the AWS services exactly as they are, we could have avoided this issue.&lt;/p&gt;

&lt;p&gt;Recently, I discovered LocalStack, a cloud development platform that addresses exactly the challenges I’ve been facing. To my surprise, it’s been around since 2016. That made me feel like I’d been living under a rock, but at the same time, there’s so much to explore in the world of tech. It’s impossible to know every tool out there — but staying curious and exploring the ones you need as you come across them is key.&lt;/p&gt;

&lt;p&gt;Since discovering LocalStack, I’ve been testing out its services, and I can honestly say it’s been a series of "wow" moments. "Wow, that was fast," "Wow, I can actually do this locally," and "Wow, this could really save me time!" It’s been exciting to see how LocalStack can replicate AWS services locally with such ease.&lt;/p&gt;

&lt;p&gt;Because of this, I’ve decided to create a series that walks through how to use each service offered by LocalStack. By combining the steps in this series with LocalStack’s documentation, I believe you’ll be able to truly keep your local development, well, local (pun intended!). This way, you can work more efficiently and avoid the pitfalls I’ve encountered.&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>aws</category>
      <category>softwaredevelopment</category>
      <category>cloud</category>
    </item>
    <item>
      <title>How to Integrate Next-Auth with Your Next.js Application</title>
      <dc:creator>Faruq Abdulsalam</dc:creator>
      <pubDate>Tue, 16 Jul 2024 12:50:07 +0000</pubDate>
      <link>https://dev.to/nagatodev/how-to-integrate-next-auth-with-your-nextjs-application-4mn9</link>
      <guid>https://dev.to/nagatodev/how-to-integrate-next-auth-with-your-nextjs-application-4mn9</guid>
      <description>&lt;p&gt;Recently, I migrated a frontend application from an older version of Next.js to Next.js 14. During this process, I decided to upgrade the session handling approach. After extensive research, I chose to use NextAuth.js, now known as Auth.js.&lt;/p&gt;

&lt;p&gt;In the application, server-side authentication with AWS Cognito is utilized, and I wanted to maintain this setup. The goal was to seamlessly integrate authentication tokens and user data retrieved from successful authentications into Auth.js, ensuring session availability across the entire app and enabling authorization enforcement for different pages.&lt;/p&gt;

&lt;p&gt;In this article, I'll guide you through the process of successfully integrating Auth.js with your Next.js application using the app router. We will cover both the credentials (email and password) approach and Google social login.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Next-Auth v5 is still in beta mode, so I wouldn't fully recommend integrating it into a production application just yet. However, the final decision is up to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Familiarity with the basics of React.js&lt;/li&gt;
&lt;li&gt;Brief experience with Next.js app router&lt;/li&gt;
&lt;li&gt;Basic understanding of Typescript, as we'll be using Next.js with TypeScript&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You don't need to have prior experience with Next-Auth.js (now Auth.js) to follow this article. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For the rest of the article,  I’ll be using &lt;code&gt;next-auth&lt;/code&gt; and &lt;code&gt;Auth.js&lt;/code&gt; interchangeably.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's get started!!&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;1. Create your Next.js application&lt;/strong&gt;&lt;br&gt;
Start by generating a new Next.js application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-next-app@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the command above, follow the prompts, accepting the defaults for TypeScript and Tailwind CSS as we'll be using TypeScript and will apply minor styling with Tailwind. Also choose &lt;code&gt;Yes&lt;/code&gt; for the import alias and accept the default alias configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Install Auth.js&lt;/strong&gt;&lt;br&gt;
Install the latest version of auth.js using npm or yarn&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install next-auth@beta
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add next-auth@beta
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Generate and Configure Your Environment Variables&lt;/strong&gt; &lt;br&gt;
Create a .env.local file and add your Auth.js secret. Auth.js uses this for encryption of your JWTs and cookies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch .env.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate the secret string by running any of the two commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Linux/Mac terminal
openssl rand -base64 33

# Alternatively, use `auth` to generate the secret
npx auth secret
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the generated secret to your &lt;code&gt;.env.local&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AUTH_SECRET="your-secret"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can escape running into major issues when you don't set this in your development environment. But it is compulsory to set it in the production environment.&lt;/p&gt;

&lt;p&gt;You should also add your backend URL here&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NEXT_PUBLIC_BASE_URL="your-backend-url"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Create your interface and types.&lt;/strong&gt;&lt;br&gt;
To manage your types effectively, create a new directory named &lt;code&gt;types&lt;/code&gt; in your root directory (or in your /src directory if you are using it), then inside it, add two new files: &lt;code&gt;login.ts&lt;/code&gt; and &lt;code&gt;user.ts&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── app
├── public
├── types
│   ├── login.ts
│   ├── user.ts
├── .env.local
└── ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your app directory should look something like this with some other files and folders which are not shown here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;login.ts&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
Add the following types for different authentication scenarios:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type CredentialsType = {
  username: string;
  password: string;
};

type SocialCredentialsType = {
  auth_code: string;
};

export type { CredentialsType, SocialCredentialsType };

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;CredentialsType&lt;/code&gt;: Defines the structure for email and password login credentials.&lt;br&gt;
&lt;code&gt;SocialCredentialsType&lt;/code&gt;: Defines the structure for social login credentials, specifically for Google authentication.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;user.ts&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
Define interface and type for user data to manage session details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface UserType {
  id: string;
  name: string;
  email: string;
  avatar: string;
  premiumSubscription: boolean;
  accessToken: string;
  refreshToken: string;
  subId: string;
}

type UserResponseType = {
  id: string;
  name: string;
  email: string;
  avatar: string;
  premium_subscription: boolean;
  access_token: string;
  refresh_token: string;
  sub_id: string;
};

export type { UserType, UserResponseType };

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;UserType&lt;/code&gt;: Interface specifying the expected properties for user session management.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UserResponseType&lt;/code&gt;: Type specifying the format of user data as received from the backend.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. Create your Auth.js configuration.&lt;/strong&gt;&lt;br&gt;
Create a new file named &lt;code&gt;auth.ts&lt;/code&gt; in your root directory. If you are using the &lt;code&gt;src/&lt;/code&gt; directory approach, place the file directly within the &lt;code&gt;src/&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── app
├── public
├── types
│   ├── login.ts
│   ├── user.ts
├── .env.local
├── auth.ts
└── ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;auth.ts&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
At the top of the file import the necessary libraries and types for &lt;br&gt;
configuring Auth.js.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// library imports
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";

// types imports
import type { NextAuthConfig, Session, User } from "next-auth";
import type { UserType, UserResponseType } from "@/types/user";
import { AdapterUser } from "next-auth/adapters";
import { CredentialsType, SocialCredentialsType } from "@/types/login";
import { JWT } from "next-auth/jwt";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we have to modify some of the types in the next-auth library with some of our own properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;declare module "next-auth" {
  interface User extends UserType {}
}

declare module "next-auth/adapters" {
  interface AdapterUser extends UserType {}
}

declare module "next-auth/jwt" {
  interface JWT extends UserType {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we used the TypeScript module augmentation feature to extend   the &lt;code&gt;User&lt;/code&gt;, &lt;code&gt;AdapterUser&lt;/code&gt;, &lt;code&gt;JWT&lt;/code&gt; interfaces from NextAuth with properties defined in &lt;code&gt;UserType&lt;/code&gt; from our &lt;code&gt;user.ts&lt;/code&gt; file. This ensures that our custom user properties are recognized throughout the Auth.js configuration.&lt;/p&gt;

&lt;p&gt;Next we declare &lt;code&gt;authOptions&lt;/code&gt; object which we'll use to initialize &lt;code&gt;NextAuth&lt;/code&gt; at the end.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const authOptions = {
  providers: [
// Add authentication providers here (e.g., CredentialsProvider, GoogleProvider)
  ],
  callbacks: {
 // Add custom authentication callbacks here (e.g., signIn, signOut, jwt, session)
  },
  pages: {
// Customize authentication-related pages (e.g., signIn, error)
  },
  session: {
// Configure session options (e.g., JWT settings, session management)
  },
} satisfies NextAuthConfig;

export const { handlers, auth, signIn, signOut } = NextAuth(authOptions);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;A.providers:&lt;/strong&gt; accepts an array of providers such as CredentialsProvider, GoogleProvider, e.t.c.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B.callbacks:&lt;/strong&gt; specifies custom callback functions that can be triggered at various points in the authentication process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C.pages:&lt;/strong&gt; auth.js has default authentication-related pages for signIn, error, signOut e.t.c. But in this block , we can override it with our  customized pages by specifying their paths.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;D.session:&lt;/strong&gt; Configures session options, such as how sessions are handled and stored. e.g jwt or database approach&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finally, we initialize &lt;code&gt;NextAuth&lt;/code&gt; with the &lt;code&gt;authOptions&lt;/code&gt; configuration and destructure the returned methods (handlers, auth, signIn, signOut) for use in our application.

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;handlers&lt;/code&gt;: Middleware for handling NextAuth requests.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;auth&lt;/code&gt;: A universal method to interact with Auth.js in your Next.js app.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;signIn&lt;/code&gt;: Method to trigger sign-in.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;signOut&lt;/code&gt;: Method to trigger sign-out.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The code in the &lt;code&gt;auth.ts&lt;/code&gt; file should look like this now&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// library imports
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";

// types imports
import type { NextAuthConfig, Session, User } from "next-auth";
import type { UserType, UserResponseType } from "@/types/user";
import { AdapterUser } from "next-auth/adapters";
import { CredentialsType, SocialCredentialsType } from "@/types/login";
import { JWT } from "next-auth/jwt";

declare module "next-auth" {
  interface User extends UserType {}
}

declare module "next-auth/adapters" {
  interface AdapterUser extends UserType {}
}

declare module "next-auth/jwt" {
  interface JWT extends UserType {}
}

const authOptions = {
  providers: [
  ],
  callbacks: {
  },
  pages: {
  },
  session: {
  },
} satisfies NextAuthConfig;

export const { handlers, auth, signIn, signOut } = NextAuth(authOptions);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's complete the &lt;code&gt;authOptions&lt;/code&gt; object with the necessary values.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A. providers&lt;/strong&gt;:&lt;br&gt;
We will use &lt;code&gt;CredentialsProvider&lt;/code&gt; for handling authentication on the server side by making requests to our server URL. We will set it up twice: once for email and password login, and once for social login with Google. To distinguish between the two, we specify unique id values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;providers: [
    CredentialsProvider({
      id: "credentials",
      name: "Credentials",
      authorize: async (credentials) =&amp;gt; {
        try {
          const user = await fetchUser(
            `${process.env.NEXT_PUBLIC_BASE_URL}/auth/login`,
            {
              username:
                typeof credentials.username === "string"
                  ? credentials.username
                  : "",
              password:
                typeof credentials.password === "string"
                  ? credentials.password
                  : "",
            }
          );

          return user ? createUser(user) : null;
        } catch (error) {
          console.error("Error during authentication", error);
          return null;
        }
      },
    }),
    CredentialsProvider({
      id: "social",
      name: "Custom Social Login",
      authorize: async (credentials) =&amp;gt; {
        try {
          const user = await fetchUser(
            `${process.env.NEXT_PUBLIC_BASE_URL}/auth/social_login`,
            {
              auth_code:
                typeof credentials.authCode === "string"
                  ? credentials.authCode
                  : "",
            }
          );

          return user ? createUser(user) : null;
        } catch (error) {
          console.error("Error during authentication", error);
          return null;
        }
      },
    }),
  ],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Email and Password Login&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first &lt;code&gt;CredentialsProvider&lt;/code&gt; is configured for email and password login.&lt;/li&gt;
&lt;li&gt;It makes a request to &lt;code&gt;${process.env.NEXT_PUBLIC_BASE_URL}/auth/login&lt;/code&gt; with the provided credentials via the fetchUser function(replace this URL with your backend URL).&lt;/li&gt;
&lt;li&gt;If a user is found, &lt;code&gt;createUser(user)&lt;/code&gt; is called to format the user data. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Social Login with Google&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The second &lt;code&gt;CredentialsProvider&lt;/code&gt; is configured for social login using Google.&lt;/li&gt;
&lt;li&gt;It makes a request to &lt;code&gt;${process.env.NEXT_PUBLIC_BASE_URL}/auth/social_login&lt;/code&gt; with the provided auth code via the &lt;code&gt;fetchUser&lt;/code&gt; function(replace this URL with your backend URL).&lt;/li&gt;
&lt;li&gt;If a user is found, &lt;code&gt;createUser(user)&lt;/code&gt; is called to format the user data.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Each provider has a unique &lt;code&gt;id&lt;/code&gt; to distinguish between the two methods of authentication.&lt;/p&gt;

&lt;p&gt;By using &lt;code&gt;CredentialsProvider&lt;/code&gt; twice with different &lt;code&gt;id&lt;/code&gt; values, we can manage multiple authentication methods seamlessly.&lt;/p&gt;

&lt;p&gt;Here are the definitions of the &lt;code&gt;fetchUser&lt;/code&gt; and &lt;code&gt;createUser&lt;/code&gt; functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Function to authenticate and fetch user details
async function fetchUser(
  url: string,
  body: CredentialsType | SocialCredentialsType
) {
  try {
    const res = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(body),
    });

    const user = await res.json();

    if (res.ok &amp;amp;&amp;amp; user) {
      return user;
    } else {
      console.error(`Failed to fetch user: ${res.status} ${res.statusText}`);
      return null;
    }
  } catch (error) {
    console.error(`Error during fetch: ${error}`);
    return null;
  }
}

// Function to create a user object
function createUser(user: UserResponseType) {
  const userObject: UserType = {
    id: user.id,
    name: user.name,
    email: user.email,
    avatar: user.avatar,
    premiumSubscription: user.premium_subscription,
    accessToken: user.access_token,
    refreshToken: "", //add subId from the auth service here
    subId: "", // add refresh token here
  };

  return userObject;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;B. callbacks&lt;/strong&gt;:&lt;br&gt;
The &lt;code&gt;callbacks&lt;/code&gt; section allows us to customize the behavior of the authentication process. Here, we’ll add two async functions: &lt;code&gt;jwt&lt;/code&gt; and &lt;code&gt;session&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;callbacks: {
    async jwt({ token, user }: { token: JWT; user: User }) {
      // Add the user properties to the token after signing in
      if (user) {
        token.id = user.id as string;
        token.avatar = user.avatar;
        token.name = user.name;
        token.email = user.email;
        token.premiumSubscription = user.premiumSubscription;
        token.accessToken = user.accessToken;
        token.subId = user.subId;
        token.refreshToken = user.refreshToken;
      }
      return token;
    },
    async session({ session, token }: { session: Session; token: JWT }) {
      // Create a user object with token properties
      const userObject: AdapterUser = {
        id: token.id,
        avatar: token.avatar,
        name: token.name,
        premiumSubscription: token.premiumSubscription,
        accessToken: token.accessToken,
        subId: token.subId,
        refreshToken: token.refreshToken,
        email: token.email ? token.email : "", // Ensure email is not undefined
        emailVerified: null, // Required property, set to null if not used
      };

      // Add the user object to the session
      session.user = userObject;

      return session;
    },
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;jwt callback&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The jwt function is called during the authentication process to add user properties to the JWT token. When a user signs in, their properties, such as id, avatar, name, email, accessToken, subId, and refreshToken, are added to the token. This token is then used to securely manage user sessions.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;session callback&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The session function is called whenever a session is accessed to add user data to the session object. A user object is created using the properties from the token. This user object is then added to the session, ensuring that user data is available whenever the session is accessed. The email property is ensured to be a string, and emailVerified is set to null if not used.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;C. pages&lt;/strong&gt;:&lt;br&gt;
In the &lt;code&gt;pages&lt;/code&gt; section of the &lt;code&gt;authOptions&lt;/code&gt; object, we define paths to our custom pages that will override the default authentication-related pages provided by Auth.js. This allows us to customize the user experience for specific authentication actions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  pages: {
    signIn: "/auth/login", // Custom sign-in page
    // error: "/auth/error", // Custom error page
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;signIn&lt;/code&gt;&lt;/strong&gt;: Specifies the path to a custom sign-in page. By setting this to &lt;code&gt;/auth/login&lt;/code&gt;, we direct users to our custom login page instead of the default Auth.js sign-in page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;error&lt;/code&gt;&lt;/strong&gt;: Optionally, we can specify a custom error page. This is commented out here, but if we wanted to use a custom error page, we could set its path like so: error: &lt;code&gt;/auth/error&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;D. session&lt;/strong&gt;:&lt;br&gt;
In the session section of the &lt;code&gt;authOptions&lt;/code&gt; object, we specify how sessions should be managed. In this case, we are using JSON Web Tokens (JWT) as the session strategy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  session: {
    strategy: "jwt",
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;strategy&lt;/code&gt;&lt;/strong&gt;: By setting this to "jwt", we ensure that sessions are managed using JSON Web Tokens. This means that session data is encoded and stored in a JWT, which is then sent to the client.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is what the entire file should look like now&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// library imports
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";

// types imports
import type { NextAuthConfig, Session, User } from "next-auth";
import type { UserType, UserResponseType } from "@/types/user";
import { AdapterUser } from "next-auth/adapters";
import { CredentialsType, SocialCredentialsType } from "@/types/login";
import { JWT } from "next-auth/jwt";

// Modify NextAuth types with custom properties
declare module "next-auth" {
  interface User extends UserType {}
}

declare module "next-auth/adapters" {
  interface AdapterUser extends UserType {}
}

declare module "next-auth/jwt" {
  interface JWT extends UserType {}
}

const authOptions = {
  providers: [
    CredentialsProvider({
      id: "credentials",
      name: "Credentials",
      authorize: async (credentials) =&amp;gt; {
        try {
          const user = await fetchUser(
            `${process.env.NEXT_PUBLIC_BASE_URL}/auth/login`,
            {
              username:
                typeof credentials.username === "string"
                  ? credentials.username
                  : "",
              password:
                typeof credentials.password === "string"
                  ? credentials.password
                  : "",
            }
          );

          return user ? createUser(user) : null;
        } catch (error) {
          console.error("Error during authentication", error);
          return null;
        }
      },
    }),
    CredentialsProvider({
      id: "social",
      name: "Custom Social Login",
      authorize: async (credentials) =&amp;gt; {
        try {
          const user = await fetchUser(
            `${process.env.NEXT_PUBLIC_BASE_URL}/auth/social_login`,
            {
              auth_code:
                typeof credentials.authCode === "string"
                  ? credentials.authCode
                  : "",
            }
          );

          return user ? createUser(user) : null;
        } catch (error) {
          console.error("Error during authentication", error);
          return null;
        }
      },
    }),
  ],
  callbacks: {
    async jwt({ token, user }: { token: JWT; user: User }) {
      // Add the user properties to the token after signing in
      if (user) {
        token.id = user.id as string;
        token.avatar = user.avatar;
        token.name = user.name;
        token.email = user.email;
        token.premiumSubscription = user.premiumSubscription;
        token.accessToken = user.accessToken;
        token.subId = user.subId;
        token.refreshToken = user.refreshToken;
      }
      return token;
    },
    async session({ session, token }: { session: Session; token: JWT }) {
      // Create a user object with token properties
      const userObject: AdapterUser = {
        id: token.id,
        avatar: token.avatar,
        name: token.name,
        premiumSubscription: token.premiumSubscription,
        accessToken: token.accessToken,
        subId: token.subId,
        refreshToken: token.refreshToken,
        email: token.email ? token.email : "", // Ensure email is not undefined
        emailVerified: null, // Required property, set to null if not used
      };

      // Add the user object to the session
      session.user = userObject;

      return session;
    },
  },
  pages: {
    signIn: "/auth/login", // Custom sign-in page
    // error: "/auth/error", // Custom error page
  },
  session: {
    strategy: "jwt",
  },
} satisfies NextAuthConfig;

// Function to authenticate and fetch user details
async function fetchUser(
  url: string,
  body: CredentialsType | SocialCredentialsType
) {
  try {
    const res = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(body),
    });

    const user = await res.json();

    if (res.ok &amp;amp;&amp;amp; user) {
      return user;
    } else {
      console.error(`Failed to fetch user: ${res.status} ${res.statusText}`);
      return null;
    }
  } catch (error) {
    console.error(`Error during fetch: ${error}`);
    return null;
  }
}

// Function to create a user object
function createUser(user: UserResponseType) {
  const userObject: UserType = {
    id: user.id,
    name: user.name,
    email: user.email,
    avatar: user.avatar,
    premiumSubscription: user.premium_subscription,
    accessToken: user.access_token,
    refreshToken: "", //add subId from the auth service here
    subId: "", // add refresh token here
  };

  return userObject;
}

export const { handlers, auth, signIn, signOut } = NextAuth(authOptions);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. Utilize the configuration in the Next.js API route.&lt;/strong&gt;&lt;br&gt;
To integrate the &lt;code&gt;NextAuth&lt;/code&gt; configuration into a Next.js API route, follow these steps:&lt;/p&gt;

&lt;p&gt;Create a new file named &lt;code&gt;route.ts&lt;/code&gt; in the app directory at the following path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── app
│   ├── api
│   │   ├── auth
│   │   │   ├── [...nextauth]
│   │   │   │   ├──  route.ts
├── auth.ts
└── ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;route.ts&lt;/code&gt; file, add the following lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// library imports
import { handlers } from "@/auth";

export const { GET, POST } = handlers;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the top, we import the &lt;code&gt;handlers&lt;/code&gt; object from &lt;code&gt;auth.ts&lt;/code&gt;, then destructure it to extract the &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt; methods and exports them. When a request is made to the &lt;code&gt;/api/auth&lt;/code&gt; endpoint, the &lt;code&gt;route.ts&lt;/code&gt; file delegates the request to the appropriate handler (&lt;code&gt;GET&lt;/code&gt; or &lt;code&gt;POST&lt;/code&gt;) provided by NextAuth. These handlers manage the authentication logic, session management, and other related tasks based on the configuration we defined earlier in &lt;code&gt;auth.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We are done with setting up &lt;code&gt;Auth.js&lt;/code&gt;. Now let's use the magic we created and see it in action&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;7. Using Auth.js in our Next.js Application&lt;/strong&gt;&lt;br&gt;
Now that we have completed the setup for &lt;code&gt;Auth.js&lt;/code&gt;, it's time to see it in action. We'll integrate authentication into our application by creating email and password sign-in, social login and protected pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A. Create the authentication components&lt;/strong&gt;&lt;br&gt;
First, create a components directory in the root directory of your app (in the &lt;code&gt;src/&lt;/code&gt; directory if you are using this approach). Then add &lt;code&gt;auth&lt;/code&gt; and &lt;code&gt;protected&lt;/code&gt; directories in it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new file named &lt;code&gt;login.tsx&lt;/code&gt; in the &lt;code&gt;components/auth&lt;/code&gt; directory and a new file named &lt;code&gt;profile.tsx&lt;/code&gt; in the &lt;code&gt;components/profile&lt;/code&gt; directory:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── app
├── components
│   ├── auth
│   │   ├── login.tsx
│   ├── profile
│   │   ├── profile.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;login.tsx&lt;/code&gt;&lt;/strong&gt;:
Here we will add the following code to create a sign-in form and a google login button.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"use client";

// library imports
import React, { useState, useEffect } from "react";
import Link from "next/link";
import { useSearchParams } from "next/navigation";

export default function SignIn() {
  const searchParams = useSearchParams();
  const googleLogin = "Your google login url which will contain your client id and redirectURI";

  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [authenticated, setAuthenticated] = useState(false);
  const [error, setError] = useState("");

  useEffect(() =&amp;gt; {
    if (authenticated) {
      // Redirect to previous page or home page
      const next = searchParams.get("next") || "/";
      window.location.href = next;
    }
  }, [authenticated]);

  const handleSubmit = async (e: React.FormEvent&amp;lt;HTMLFormElement&amp;gt;) =&amp;gt; {
    e.preventDefault();
    try {
      const res = await fetch("/api/login", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ username, password, type: "credentials" }),
      });

      if (res.ok) {
        setAuthenticated(true);
      } else {
        // handle error state here
        setError("Invalid credentials");
      }
    } catch (error) {
      // handle error state here
      console.error("Error during sign-in", error);
      setError("Internal server error");
    }
  };

return (
    &amp;lt;div className="mx-auto w-[200px] h-full border-red-100"&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;p className="text-xl w-full flex justify-center mt-3 mb-5"&amp;gt;Sign In&amp;lt;/p&amp;gt;
        &amp;lt;form onSubmit={handleSubmit}&amp;gt;
          &amp;lt;label&amp;gt;
            Username:
            &amp;lt;input
              type="text"
              className="w-full rounded-sm"
              value={username}
              onChange={(e) =&amp;gt; setUsername(e.target.value)}
            /&amp;gt;
          &amp;lt;/label&amp;gt;
          &amp;lt;label&amp;gt;
            Password:
            &amp;lt;input
              className="w-full rounded-sm"
              type="password"
              value={password}
              onChange={(e) =&amp;gt; setPassword(e.target.value)}
            /&amp;gt;
          &amp;lt;/label&amp;gt;
          &amp;lt;button
            className="w-full flex justify-center bg-teal-500 text-white mt-3 rounded-md"
            type="submit"
          &amp;gt;
            Sign In
          &amp;lt;/button&amp;gt;
          {error &amp;amp;&amp;amp; &amp;lt;p style={{ color: "red" }}&amp;gt;{error}&amp;lt;/p&amp;gt;}
        &amp;lt;/form&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div className="my-2"&amp;gt;
        &amp;lt;div className="flex justify-center"&amp;gt; or &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div className="w-full bg-red-700 rounded-md mb-2"&amp;gt;
        &amp;lt;Link href={googleLogin} className="flex "&amp;gt;
          &amp;lt;p className="w-full text-white flex justify-center"&amp;gt;
            Sign in with Google
          &amp;lt;/p&amp;gt;
        &amp;lt;/Link&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;


&lt;p&gt;We'll send a POST request to an API route (/api/login) to handle authentication. If the login is successful, the user will be redirected to the next page or home page. If the &lt;code&gt;Sign in with Google&lt;/code&gt; button is clicked, the user will be redirected to the &lt;code&gt;google-login&lt;/code&gt; page&lt;/p&gt;

&lt;p&gt;Next, we will create the &lt;code&gt;/api/login&lt;/code&gt; endpoint to handle the authentication logic on the server side. Create a new folder named &lt;code&gt;login&lt;/code&gt; in the &lt;code&gt;app/api&lt;/code&gt; directory and create a &lt;code&gt;route.ts&lt;/code&gt; file in it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── app
│   ├── api
│   │   ├── auth
│   │   ├── login
│   │   │   ├── route.ts
├── components
├── auth.ts
└── ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;route.ts&lt;/code&gt;&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// library imports
import { NextResponse, NextRequest } from "next/server";

// internal imports
import { signIn } from "@/auth";

export async function POST(req: NextRequest, res: NextResponse) {
  const data = await req.json();
  const { username, password, type } = data;

  try {
    const result =
      type === "credentials"
        ? await signIn("credentials", { redirect: false, username, password })
        : await signIn("social", { redirect: false, authCode: username });

    // handle the result of the sign-in attempt
    if (!result || result.error) {
      return NextResponse.json({ error: "Invalid credentials" });
    } else {
      return NextResponse.json({ success: true });
    }
  } catch (error) {
    console.error("Error during sign-in", error);
    return NextResponse.error();
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we handle authentication for both credentials and social login types. Based on the &lt;code&gt;type&lt;/code&gt; of login, we call the signIn function with either credentials (&lt;code&gt;username and password&lt;/code&gt;) or social login (&lt;code&gt;auth_code&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Next, we will create the social login page. Create a new file named &lt;code&gt;socialAuth.tsx&lt;/code&gt; in the &lt;code&gt;components/auth&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── app
├── components
│   ├── auth
│   │   ├── login.tsx
│   │   ├── socialAuth.tsx
│   ├── profile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;socialAuth.tsx&lt;/code&gt;&lt;/strong&gt;:
Add the following code to socialAuth.tsx.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"use client";

// library imports
import React, { useState, useEffect } from "react";
import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";

export default function SocialAuth() {
  const googleLogin =
    "Your google login url which will contain your client id and redirectURI";

  const router = useRouter();
  const searchParams = useSearchParams();

  const [authSuccess, setAuthSuccess] = useState(true);
  const [tokenStatus, setTokenStatus] = useState(false);

  useEffect(() =&amp;gt; {
    // check query string for authentication code
    if (authSuccess || tokenStatus) {
      const url = window.location.href;
      const code = url.match(/\?code=(.*)/);
      if (!tokenStatus &amp;amp;&amp;amp; authSuccess) {
        if (code) {
          authenticateUser(code[1]);
        } else {
          router.push("/auth/login");
        }
      } else if (tokenStatus) {
        // Redirect to previous page or home page
        const next = searchParams.get("next") || "/";
        router.push(next);
      } else {
        router.push("/auth/login");
      }
    }
  }, [tokenStatus, authSuccess]);

  const authenticateUser = async (code: string) =&amp;gt; {
    try {
      const res = await fetch("/api/login", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ username: code, type: "social" }),
      });

      if (res.ok) {
        setTokenStatus(true);
      } else {
        // handle error state here
        setAuthSuccess(false);
      }
    } catch (error) {
      // handle error state here
      setAuthSuccess(false);
    }
  };

  return (
    &amp;lt;&amp;gt;
      &amp;lt;div&amp;gt;
        {authSuccess ? (
          &amp;lt;div&amp;gt;
            &amp;lt;h1&amp;gt;Authenticating...&amp;lt;/h1&amp;gt;
          &amp;lt;/div&amp;gt;
        ) : (
          &amp;lt;div&amp;gt;
            &amp;lt;h1&amp;gt;
              {" "}
              An error occurred while attempting to authenticate your account
              with Google{" "}
            &amp;lt;/h1&amp;gt;

            &amp;lt;div&amp;gt;
              &amp;lt;div&amp;gt;
                &amp;lt;Link href={googleLogin}&amp;gt;Please try again&amp;lt;/Link&amp;gt;
              &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
          &amp;lt;/div&amp;gt;
        )}
      &amp;lt;/div&amp;gt;
    &amp;lt;/&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that users can authenticate via social login providers like Google and handles the authentication flow smoothly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B. Create the Authentication Pages&lt;/strong&gt;&lt;br&gt;
Next, let's create the custom &lt;code&gt;sign-in&lt;/code&gt; and &lt;code&gt;social login&lt;/code&gt; pages that utilize the components we created above.&lt;/p&gt;

&lt;p&gt;Create a new directory called &lt;code&gt;auth&lt;/code&gt; in the &lt;code&gt;app/&lt;/code&gt; directory. Inside &lt;code&gt;auth&lt;/code&gt;, create folders named &lt;code&gt;login&lt;/code&gt; and &lt;code&gt;social&lt;/code&gt;, and then add a &lt;code&gt;page.tsx&lt;/code&gt; file in both folders.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── app
│   ├── auth
│   │   ├── login
│   │   │   ├── page.tsx
│   │   ├── social
│   │   │   ├── page.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In &lt;code&gt;login/page.tsx&lt;/code&gt;, add the following code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//component imports
import SignIn from "@/components/auth/login";

export default function LoginPage() {
  return &amp;lt;SignIn /&amp;gt;;
}

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In &lt;code&gt;social/page.tsx&lt;/code&gt;, add the following code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//component imports
import SocialAuth from "@/components/auth/socialAuth";

export default function SocialAuthPage() {
  return &amp;lt;SocialAuth /&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are now set with authentication, and you can confirm the state of what we have done so far.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Attempt to navigate to this url &lt;code&gt;http://localhost:3000/api/auth/signin&lt;/code&gt;. You should be redirected back to the custom sign-in page. This redirection occurs because of the URL path we specified in the &lt;code&gt;pages&lt;/code&gt; section of our &lt;code&gt;authOptions&lt;/code&gt; object while setting up the configuration in &lt;code&gt;auth.ts&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;B. Create protected page&lt;/strong&gt;&lt;br&gt;
The final step is to create a protected page that users cannot access unless they are authenticated.&lt;/p&gt;

&lt;p&gt;-&lt;strong&gt;&lt;code&gt;profile.tsx&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
Let's add the code below to our empty file &lt;code&gt;profile.tsx&lt;/code&gt; in the components directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"use client";

// library imports
import React, { useState, useEffect } from "react";
import { useSession } from "next-auth/react";
import { useRouter, usePathname } from "next/navigation";

export default function Profile() {
  const router = useRouter();
  const pathname = usePathname();

  const { data: session } = useSession();

  const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;

  const [loadingProfile, setLoadingProfile] = useState(false);

  useEffect(() =&amp;gt; {
    if (session?.user?.accessToken) {
      // fetch user profile if access token is available
      getUserProfile(session.user.accessToken);
    } else {
      // Redirect to `/login` if no access token or no session
      router.push("/auth/login?next=" + pathname);
    }
  }, []);

  const getUserProfile = (token: string) =&amp;gt; {
    setLoadingProfile(true);
    fetch(`${baseUrl}/auth/user_profile`, {
      headers: { Authorization: "Bearer " + token },
    })
      .then((response) =&amp;gt; {
        setLoadingProfile(false);
      })
      .catch((error) =&amp;gt; {
        // handle error here
        console.error(error);
      });
  };

  return (
    &amp;lt;&amp;gt;
      {" "}
      {loadingProfile ? (
        &amp;lt;p&amp;gt;Loading...&amp;lt;/p&amp;gt;
      ) : (
        &amp;lt;div&amp;gt;
          &amp;lt;p&amp;gt;User Profile&amp;lt;/p&amp;gt;
          &amp;lt;p&amp;gt;Name: {session?.user?.name}&amp;lt;/p&amp;gt;
          &amp;lt;p&amp;gt;Email: {session?.user?.email}&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
      )}
    &amp;lt;/&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;Here we use the &lt;code&gt;useSession&lt;/code&gt; hook to check if a user session with an access token exists. If the token is present , we go ahead and make a call to the backend route &lt;code&gt;/auth/user_profile&lt;/code&gt; . In my case i have a protected route in the backend which an unauthenticated user cannot access without a token. While waiting for the profile data to load, a loading indicator is displayed. Once loaded, the component displays the user's name and email. If there is no active session or access token, it redirects the user back to the login page to authenticate.&lt;/p&gt;

&lt;p&gt;Finally, we create the page which utilizes the &lt;code&gt;profile.tsx&lt;/code&gt; component above. Create a new folder in the app directory named &lt;code&gt;profile&lt;/code&gt; and in it a &lt;code&gt;page.tsx&lt;/code&gt; file. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;page.tsx&lt;/code&gt;&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// library imports
import { SessionProvider } from "next-auth/react";

// internal imports
import { auth } from "@/auth";

//component imports
import Profile from "@/components/profile/profile";

export default async function ProfilePage() {
  const session = await auth();

  return (
    &amp;lt;SessionProvider session={session}&amp;gt;
      &amp;lt;Profile /&amp;gt;
    &amp;lt;/SessionProvider&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First we import the &lt;code&gt;SessionProvider&lt;/code&gt; component from &lt;code&gt;next-auth/react&lt;/code&gt; to serve as a context provider for managing the user session state throughout the application. Additionally, we import the &lt;code&gt;auth&lt;/code&gt; method from &lt;code&gt;auth.js&lt;/code&gt;. Since this operation requires asynchronous behavior, we utilize a server-side component, using &lt;code&gt;await&lt;/code&gt; to fetch the session using the &lt;code&gt;auth&lt;/code&gt; method. Subsequently, we pass this session object obtained from auth to the &lt;code&gt;SessionProvider&lt;/code&gt; component which acts as a wrapper around the &lt;code&gt;Profile&lt;/code&gt; component. We have to wrap the component with Session Provider here if we want the session to be accessible within &lt;code&gt;profile.tsx&lt;/code&gt; using the &lt;code&gt;useSession&lt;/code&gt; hook, similar to how we handled authentication state above.&lt;/p&gt;

&lt;p&gt;Now if we try to access the &lt;code&gt;/profile&lt;/code&gt; route, we would get redirected to the &lt;code&gt;/auth/login&lt;/code&gt; page since we are not logged in. Once we login, we would be redirected back to the profile page, where we can see our user data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Congratulations , you have successfully integrated your next js application using the app router with auth.js v5.
&lt;/h2&gt;

&lt;p&gt;You might have noticed that in the profile.tsx component, we check the session for a token and then redirect the user back to the login page if the token is not present. This means that Next.js already starts rendering our page before redirecting to the login page if the token is absent. If you pay attention, you'll also notice this in the UI.&lt;/p&gt;

&lt;p&gt;An alternative to this approach is to use middleware to handle authentication. Next.js has a middleware feature that is triggered when a user attempts to access a route. We can use this to protect our authenticated routes. This way, the protected page is not rendered if an unauthenticated user attempts to access it, as the middleware intercepts the request and redirects the user to the login route. This ensures we have a central location to check the session and redirect users if they are unauthenticated, thereby improving the user experience with the UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Adding a Middleware&lt;/strong&gt;&lt;br&gt;
Create a new file called &lt;code&gt;middleware.ts&lt;/code&gt; in your root directory. If you are using the &lt;code&gt;src/&lt;/code&gt; directory approach, place the file directly within the &lt;code&gt;src/&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── app
├── public
├── types
├── .env.local
├── auth.ts
├── middleware.ts
└── ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;-&lt;strong&gt;&lt;code&gt;middleware.ts&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
In the file add the following lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { NextResponse } from "next/server";
import { auth } from "@/auth";

export default auth((req) =&amp;gt; {
  const currentPath = req.nextUrl.pathname;

  // Redirect to login page if user is not authenticated
  if (!req.auth) {
    return NextResponse.redirect(
      new URL(`/auth/login?next=${currentPath}`, req.url)
    );
  }
});

// Manage list of protected routes
export const config = {
  matcher: ["/profile/:path*", "/another-protected-route/:path*"],
};

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

&lt;/div&gt;



&lt;p&gt;This middleware checks if the user is authenticated before allowing access to specified routes. If the user is not authenticated, they are redirected to the login page. The config object defines the routes that should trigger this middleware, ensuring that only protected routes are affected.&lt;/p&gt;

&lt;p&gt;By setting up this middleware, you centralize the authentication logic, making your codebase cleaner and more maintainable as your application grows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Note&lt;/code&gt;&lt;/strong&gt;: In my application, I have several authenticated and unauthenticated routes, which is why I am not triggering the middleware with all requests and instead maintaining a protected routes list. The little downside to this is that you have to manage a list of all your protected routes. This might end up becoming a long list and could become difficult to manage, or someone might implement a protected page and forget to update the middleware. If your base path is the only unprotected route, your job will be much easier.&lt;/p&gt;

&lt;p&gt;It's been a long ride, but we have finally come to the end of this tutorial. With what you have learned, I believe you can seamlessly integrate &lt;code&gt;Auth.js v5&lt;/code&gt; into your `next.js application.  &lt;/p&gt;

&lt;p&gt;Here is the link to the &lt;a href="https://github.com/Faruqt/next-14-authjs" rel="noopener noreferrer"&gt;github repo&lt;/a&gt; for this project. Cheers!!!&lt;/p&gt;

&lt;p&gt;If you have any questions, feel free to drop them as a comment or send me a message on &lt;a href="https://www.linkedin.com/in/faruq-abdulsalam/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and I'll ensure I respond as quickly as I can. Ciao 👋&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to add login authentication to a Flask and React application.</title>
      <dc:creator>Faruq Abdulsalam</dc:creator>
      <pubDate>Tue, 21 Dec 2021 08:14:51 +0000</pubDate>
      <link>https://dev.to/nagatodev/how-to-add-login-authentication-to-a-flask-and-react-application-23i7</link>
      <guid>https://dev.to/nagatodev/how-to-add-login-authentication-to-a-flask-and-react-application-23i7</guid>
      <description>&lt;p&gt;In &lt;code&gt;flask&lt;/code&gt;, adding authentication has been made quite easy with the &lt;code&gt;@login_required&lt;/code&gt; decorator in the flask extension &lt;code&gt;Flask-login&lt;/code&gt;. I have an article on how to add basic authentication to your flask application that you can read up on &lt;a href="https://dev.to/nagatodev/adding-authentication-to-a-flask-application-53ep"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, since you will be working with API endpoints you can't use the approach above because the &lt;code&gt;@login_required&lt;/code&gt; decorator redirects to the application to an &lt;code&gt;HTML page&lt;/code&gt; when it discovers a user that is not authenticated trying to access a protected page. This defeats the idea of creating API endpoints as APIs are only designed to return data in &lt;code&gt;json&lt;/code&gt; format.&lt;/p&gt;

&lt;p&gt;In this part of the series, you'll be learning how to add authentication to the connected React and Flask application you built in the previous part of the series. Authentication will be done with the flask extension: &lt;a href="https://flask-jwt-extended.readthedocs.io/en/stable/basic_usage/" rel="noopener noreferrer"&gt;flask-jwt-extended&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;1) Beginner-level understanding of the flask framework. If you are new to &lt;code&gt;Flask&lt;/code&gt; you can check out my &lt;a href="https://dev.to/nagatodev/getting-started-with-flask-1kn1"&gt;article&lt;/a&gt; on how to set up your flask project and use it with the &lt;a href="https://palletsprojects.com/p/jinja/" rel="noopener noreferrer"&gt;jinja&lt;/a&gt; template engine. &lt;/p&gt;

&lt;p&gt;2) I strongly advise you to read the previous &lt;a href="https://dev.tohello"&gt;article&lt;/a&gt;. You can also get the files in the Github &lt;a href="https://github.com/Faruqt/React-Flask" rel="noopener noreferrer"&gt;repo&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;3) Familiarity with the basics of &lt;code&gt;ReactJs&lt;/code&gt;. You will be making use of the &lt;code&gt;useState&lt;/code&gt; hook, fetching data from API endpoints using &lt;code&gt;axios&lt;/code&gt; and also using &lt;code&gt;react-router-dom&lt;/code&gt; to handle routing of components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's get started!!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Flask Backend
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Installing the flask extension.
&lt;/h3&gt;

&lt;p&gt;Navigate into the &lt;code&gt;backend&lt;/code&gt; directory and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pip&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;extended&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;note:&lt;/strong&gt; If you cloned the repo, you don't need to run the command above, just set up your flask application with the instructions in the &lt;code&gt;README.md&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  base.py
&lt;/h3&gt;

&lt;p&gt;You'll be adding authentication to the &lt;code&gt;/profile&lt;/code&gt; API endpoint created in the previous tutorial. Navigate to the &lt;code&gt;base.py&lt;/code&gt; script you created in the backend directory of your application to create the token(login) and logout API endpoints.&lt;/p&gt;

&lt;h3&gt;
  
  
  token(login) API endpoint
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jsonify&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timezone&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_jwt_extended&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;create_access_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;get_jwt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;get_jwt_identity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
                               &lt;span class="nx"&gt;unset_jwt_cookies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jwt_required&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JWTManager&lt;/span&gt;


&lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JWT_SECRET_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;please-remember-to-change-me&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;jwt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JWTManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_token&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;msg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Wrong email or password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;

    &lt;span class="nx"&gt;access_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_access_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;access_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_profile&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nx"&gt;response_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nagato&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;about&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello! I'm a full stack developer that loves python and javascript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response_body&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's go through the code above:&lt;/p&gt;

&lt;p&gt;First, the required functions are imported from the installed &lt;code&gt;flask_jwt_extended&lt;/code&gt; extension.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_jwt_extended&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;create_access_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;get_jwt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;get_jwt_identity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
                               &lt;span class="nx"&gt;unset_jwt_cookies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jwt_required&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JWTManager&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, the flask application instance is configured with the &lt;code&gt;JWT&lt;/code&gt; secret key then passed as an argument to the &lt;code&gt;JWTManager&lt;/code&gt; function and assigned to the &lt;code&gt;jwt&lt;/code&gt; variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JWT_SECRET_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;please-remember-to-change-me&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;jwt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JWTManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;token&lt;/code&gt; API endpoint will have a &lt;code&gt;POST&lt;/code&gt; request method. Whenever the user submits a login request, the email and password are extracted and compared with the hardcoded email(test) and password(test). Please &lt;strong&gt;note&lt;/strong&gt; that in an ideal scenario you are going to compare the extracted login details with data in your database.&lt;/p&gt;

&lt;p&gt;If the login details are not correct, the error message &lt;code&gt;Wrong email or password&lt;/code&gt; with the status code &lt;code&gt;401&lt;/code&gt; which means &lt;code&gt;UNAUTHORIZED Error&lt;/code&gt; is sent back to the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;msg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Wrong email or password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Else if the login details are confirmed to be correct, an access token is created for that particular email address by assigning the &lt;code&gt;email&lt;/code&gt; to the &lt;code&gt;identity&lt;/code&gt; variable. Finally, the token is returned to the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_access_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;access_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test this, start your backend server with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please &lt;strong&gt;note&lt;/strong&gt; that the command above was specified in the &lt;code&gt;package.json&lt;/code&gt; file in the react frontend. This was done in the previous part of the series. If you have not checked it out yet, please head &lt;a href="https://dev.to/nagatodev/how-to-connect-flask-to-reactjs-1k8i"&gt;there&lt;/a&gt; so you can learn how to set it up. However if you have already cloned the repo, let's proceed.&lt;/p&gt;

&lt;p&gt;Next, open up &lt;a href="https://web.postman.co/" rel="noopener noreferrer"&gt;postman&lt;/a&gt; and send a &lt;code&gt;POST&lt;/code&gt; request to this API endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//127.0.0.1:5000/token&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll get a &lt;code&gt;500 internal server&lt;/code&gt; error 👇&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6evm5ix4axj1rp2mb12o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6evm5ix4axj1rp2mb12o.png" alt="500 internal server error" width="800" height="238"&gt;&lt;/a&gt; &lt;br&gt;
Check your terminal and you'll see the error as well 👇&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7typdk0o3cso8ayb8e91.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7typdk0o3cso8ayb8e91.png" alt="terminal nonetype error" width="800" height="234"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;AttributeError: 'NoneType' object has no attribute 'get'&lt;/code&gt; the error occurred because you did not specify the login details when you made the &lt;code&gt;POST&lt;/code&gt; request to the API endpoint thus a &lt;code&gt;None&lt;/code&gt; value was passed as an argument to the &lt;code&gt;request.json.get&lt;/code&gt; function. &lt;/p&gt;

&lt;p&gt;Return to &lt;code&gt;POSTMAN&lt;/code&gt; and pass the login details along with the &lt;code&gt;POST&lt;/code&gt; request.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiifymp0j2ymp9rv8snlw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiifymp0j2ymp9rv8snlw.png" alt="login details" width="800" height="251"&gt;&lt;/a&gt;&lt;br&gt;
 Please ensure you adjust your settings as circled in the image above.&lt;/p&gt;

&lt;p&gt;After making the request you should get your access token in the form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;access_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your access token will be here&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can try to pass in a wrong email or password to see the &lt;code&gt;401 UNAUTHORIZED error&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6yccpwbuhbi27bq0isz4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6yccpwbuhbi27bq0isz4.png" alt="401 UNAUTHORIZED error" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Logout API endpoint
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/logout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;msg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logout successful&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;unset_jwt_cookies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When the &lt;code&gt;logout&lt;/code&gt; API endpoint is called, &lt;code&gt;response&lt;/code&gt; is passed to the &lt;code&gt;unset_jwt_cookies&lt;/code&gt; function which deletes the cookies containing the access token for the user and finally returns the success message to the user.&lt;/p&gt;

&lt;p&gt;Head over to &lt;code&gt;Postman&lt;/code&gt; once again and make a POST request to the &lt;code&gt;logout&lt;/code&gt; API endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//127.0.0.1:5000/logout&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get the response below 👇&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkwhgdiyrmqlzkse9juro.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkwhgdiyrmqlzkse9juro.png" alt="logout api call" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Refreshing tokens
&lt;/h3&gt;

&lt;p&gt;The generated token always has a &lt;code&gt;lifespan&lt;/code&gt; after which it expires. To ensure that this does not happen while the user is logged in, you have to create a function that refreshes the token when it is close to the end of its lifespan. &lt;/p&gt;

&lt;p&gt;First, specify the &lt;code&gt;lifespan&lt;/code&gt; for your generated tokens and add it as a new configuration for your application.&lt;br&gt;
&lt;strong&gt;Note:&lt;/strong&gt;You can change the time to suit your application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JWT_ACCESS_TOKEN_EXPIRES&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, create the function below 👇, above the &lt;code&gt;create_token&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;after_request&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;refresh_expiring_jwts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;exp_timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_jwt&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;exp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;target_timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;target_timestamp&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;exp_timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nx"&gt;access_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_access_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;get_jwt_identity&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;access_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;access_token&lt;/span&gt; 
                &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;
    &lt;span class="nf"&gt;except &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;KeyError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Case&lt;/span&gt; &lt;span class="nx"&gt;where&lt;/span&gt; &lt;span class="nx"&gt;there&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;valid&lt;/span&gt; &lt;span class="nx"&gt;JWT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Just&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt; &lt;span class="nx"&gt;respone&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;after_request&lt;/code&gt; decorator ensures that the &lt;code&gt;refresh_expiring_jwts&lt;/code&gt; function runs after a request has been made to the protected API endpoint &lt;code&gt;/profile&lt;/code&gt;. The function takes as an argument, the response from the &lt;code&gt;/profile&lt;/code&gt; API call.&lt;/p&gt;

&lt;p&gt;Then, the current expiry timestamp for the user's token is obtained and compared with the specified &lt;code&gt;timestamp&lt;/code&gt; for the token which is set at 30 minutes. You can change this as well.&lt;/p&gt;

&lt;p&gt;If the expiry timestamp for the user's token happens to be  30minutes away from expiration, the token for that user is changed to a new one with the specified 1hr lifespan, and the new token is appended to the response returned to the user. But if the token is not close to expiration, the original response is sent to the user.&lt;/p&gt;

&lt;p&gt;To conclude the backend setup, you need to add the &lt;code&gt;@jwt_required()&lt;/code&gt; decorator to the &lt;code&gt;my_profile&lt;/code&gt; function to prevent unauthenticated users from making requests to the API endpoint. But first, test the &lt;code&gt;/profile&lt;/code&gt; API endpoint by making a &lt;code&gt;GET&lt;/code&gt; request to the URL below using &lt;code&gt;Postman&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//127.0.0.1:5000/profile&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should still get the json form of the dictionary created in the last article.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzisjb8jrudw85xo1gn6u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzisjb8jrudw85xo1gn6u.png" alt="json form of profile api call" width="800" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, add the &lt;code&gt;@jwt_required()&lt;/code&gt; decorator&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;jwt_required&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_profile&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nx"&gt;response_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nagato&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;about&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello! I'm a full stack developer that loves python and javascript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response_body&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and try to make the API request to the &lt;code&gt;/profile&lt;/code&gt; endpoint using the URL above. You'll get a &lt;code&gt;401 UNAUTHORIZED error&lt;/code&gt; because the token was absent when you made the request. &lt;/p&gt;

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

&lt;p&gt;After the user logs in and gets the assigned token, the token needs to be sent with each call the user makes to the API endpoints in the backend as an &lt;code&gt;Authorization Header&lt;/code&gt; in this format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Bearer&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before you head over to the frontend, you can also test this on &lt;code&gt;Postman&lt;/code&gt; by adding the user's token to the Authorization header before you call the protected &lt;code&gt;\profile&lt;/code&gt; API endpoint.&lt;/p&gt;

&lt;p&gt;Make a &lt;code&gt;POST&lt;/code&gt; request to the endpoint below to get your token and copy it out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//127.0.0.1:5000/token&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, add the &lt;code&gt;authorization&lt;/code&gt; header key with your &lt;code&gt;token&lt;/code&gt; as its value and then send the &lt;code&gt;GET&lt;/code&gt; request, you should get a json response containing the dictionary with your name and about_me info.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3cakm1vcyb4s7p4a1w7i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3cakm1vcyb4s7p4a1w7i.png" alt="authorization header added" width="800" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations you have successfully added authentication to your API endpoint. After the changes and additions, this should be the final look of the &lt;code&gt;base.py&lt;/code&gt; script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jsonify&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timezone&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_jwt_extended&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;create_access_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;get_jwt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;get_jwt_identity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
                               &lt;span class="nx"&gt;unset_jwt_cookies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jwt_required&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JWTManager&lt;/span&gt;


&lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JWT_SECRET_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;please-remember-to-change-me&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JWT_ACCESS_TOKEN_EXPIRES&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;jwt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JWTManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;after_request&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;refresh_expiring_jwts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;exp_timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_jwt&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;exp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;target_timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;target_timestamp&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;exp_timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nx"&gt;access_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_access_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;get_jwt_identity&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;access_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;access_token&lt;/span&gt; 
                &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;
    &lt;span class="nf"&gt;except &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;KeyError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Case&lt;/span&gt; &lt;span class="nx"&gt;where&lt;/span&gt; &lt;span class="nx"&gt;there&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;valid&lt;/span&gt; &lt;span class="nx"&gt;JWT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Just&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt; &lt;span class="nx"&gt;respone&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_token&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;msg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Wrong email or password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;

    &lt;span class="nx"&gt;access_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_access_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;access_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/logout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;msg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logout successful&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;unset_jwt_cookies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;jwt_required&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_profile&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nx"&gt;response_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nagato&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;about&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello! I'm a full stack developer that loves python and javascript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response_body&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now you can head over to the react frontend where you'll be making the API endpoint calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Frontend
&lt;/h2&gt;

&lt;p&gt;In the last article, you only had to make a few changes to the &lt;code&gt;App.js&lt;/code&gt; file. But this time around major changes will be made and new components will also be created.&lt;/p&gt;

&lt;p&gt;In the frontend, a &lt;code&gt;Login&lt;/code&gt; component that will hold the login page will be created. This component will be rendered anytime it notices that an unauthenticated user is trying to access a page that contains a protected API endpoint. This will ensure that any request made to the backend has a token appended to it.&lt;/p&gt;

&lt;p&gt;To start with, create a new directory &lt;code&gt;components&lt;/code&gt; in the &lt;code&gt;src&lt;/code&gt; directory and in it, four new components &lt;code&gt;Login.js&lt;/code&gt;, &lt;code&gt;useToken.js&lt;/code&gt;, &lt;code&gt;Header.js&lt;/code&gt; and &lt;code&gt;Profile.js&lt;/code&gt;. Then navigate back to the base directory and install &lt;code&gt;react-router-dom&lt;/code&gt; before you go into the components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;dom&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Storage of token in the frontend
&lt;/h3&gt;

&lt;p&gt;The token generated from the backend needs to be stored in your web browser after you log in. Presently, that is not the case. Whenever a user refreshes his browser page, the token gets deleted and the user would be prompted to log in once again. &lt;/p&gt;

&lt;p&gt;To fix this, you'll need to make use of web storage objects: &lt;code&gt;localStorage&lt;/code&gt; or &lt;code&gt;sessionStorage&lt;/code&gt;. You can read more on that &lt;a href="https://javascript.info/localstorage" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;i)sessionStorage: The user's token gets stored in the tab currently opened in the browser. If the user refreshes the page, the token is still retained. However, if the user opens a new tab to the same page in the web browser, the token won't reflect on that page as the new tab doesn't share the same storage with the previous one. Thus, the user would be prompted to log in again.&lt;/p&gt;

&lt;p&gt;To see this in action, open any website of your choice and open up the &lt;code&gt;Developer tools&lt;/code&gt; menu with the &lt;code&gt;Inspect Element&lt;/code&gt; or &lt;code&gt;Inspect&lt;/code&gt; option by right-clicking on any page in your browser. You can also see the web storage under the &lt;code&gt;Application&lt;/code&gt; section.&lt;/p&gt;

&lt;p&gt;Open up your console and store an object sample in the web storage using the sessionStorage function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then to get the value &lt;code&gt;53&lt;/code&gt; assigned to the key &lt;code&gt;test&lt;/code&gt; above run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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%2Fyzdztspwnzrk3afunu5x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyzdztspwnzrk3afunu5x.png" alt="session and local storage test" width="800" height="669"&gt;&lt;/a&gt;&lt;br&gt;
Refresh the page and run the &lt;code&gt;getItem&lt;/code&gt; function again, you'll still get the value from the storage.&lt;/p&gt;

&lt;p&gt;Now, open the link to the same page you just worked with, in a new tab, and try to access the stored object value via the console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll get a &lt;code&gt;null&lt;/code&gt; value because the current tab doesn't have access to the storage of the previous tab. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;note:&lt;/strong&gt; while carrying out all the tests above, keep an eye on the changes occurring in the &lt;code&gt;web storage&lt;/code&gt; section above your &lt;code&gt;console&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;ii)localStorage: Here, the user's token get's stored in universal storage that can be accessed by all tabs and browser windows. The token is still retained even if the user refreshes or closes the page, creates a new tab or window, or restarts the browser entirely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;333&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then to get the assigned value &lt;code&gt;333&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try to run the duplicate test done above, you'll notice that you can access the value from the duplicated page. You can also create a new browser window, open any page of the same website and try to access the value set above. You'll notice that you still have access to it. That is the beauty of using &lt;code&gt;localStorage&lt;/code&gt;, it ensures that the user only needs to log in once and they can easily navigate to any page on the website. &lt;/p&gt;

&lt;p&gt;Whenever you are done, you can delete the object from the storage using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  useToken.js
&lt;/h3&gt;

&lt;p&gt;Now you need to replicate what was done above in your react code. Open the &lt;code&gt;useToken&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;userToken&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;userToken&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setToken&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;saveToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;removeToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;setToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;saveToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;removeToken&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;useToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the tests you carried out in the console, the functions created in the &lt;code&gt;useToken&lt;/code&gt; component should be easy to understand.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;getToken&lt;/code&gt; function is used to retrieve the &lt;code&gt;token&lt;/code&gt; stored in the &lt;code&gt;localStorage&lt;/code&gt; and only returns a token if it exists hence the use of the &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; conditional operator.&lt;/p&gt;

&lt;p&gt;The useState hook is used to handle the state of the &lt;code&gt;token&lt;/code&gt; variable which will contain the value of the token. This ensures that the react application always reloads when any of the functions are called. Such that when a user logs in and the token is stored or when the user logs out, the application also becomes aware that a change has occurred in the web storage of your browser and hence reacts accordingly by either redirecting to the page the user wants to access or returning to the login page once the user logs out.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;saveToken&lt;/code&gt; function handles the storage of the token obtained when the user logs in and the &lt;code&gt;setToken&lt;/code&gt; function in it updates the state of the &lt;code&gt;token&lt;/code&gt; variable with the &lt;code&gt;token&lt;/code&gt; passed as an argument to the &lt;code&gt;saveToken&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;removeToken&lt;/code&gt; function deletes the token from the local storage and returns the token back to the null state whenever it gets called.&lt;/p&gt;

&lt;p&gt;Finally, the &lt;code&gt;saveToken&lt;/code&gt; function assigned as a value to the setToken variable, the value of the &lt;code&gt;token&lt;/code&gt; itself and the &lt;code&gt;removeToken&lt;/code&gt; function are all returned as the result of calling the &lt;code&gt;useToken&lt;/code&gt; function.&lt;/p&gt;

&lt;h3&gt;
  
  
  App.js
&lt;/h3&gt;

&lt;p&gt;I told you that you'll be making major changes right? 😜. Clean up &lt;code&gt;App.js&lt;/code&gt;; all the code that was added the last time will be moved into the &lt;code&gt;Profile&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BrowserRouter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Login&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/Login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Profile&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/Profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/Header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useToken&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/useToken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;removeToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setToken&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BrowserRouter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;removeToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="o"&gt;!==&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;  
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt; &lt;span class="nx"&gt;setToken&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;:(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Routes&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;exact&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Profile&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;setToken&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&amp;gt;}&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Routes&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/BrowserRouter&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;At the top of the file, the &lt;code&gt;BrowserRouter&lt;/code&gt;, &lt;code&gt;Route&lt;/code&gt;, &lt;code&gt;Routes&lt;/code&gt; functions that will be used to handle URL routing for the profile component are imported from the installed &lt;code&gt;react-router-dom&lt;/code&gt; package. The other created components are also imported from the &lt;code&gt;components&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;App&lt;/code&gt; function, the value object returned when the &lt;code&gt;useToken&lt;/code&gt; function is called is destructured and the values are assigned to the &lt;code&gt;token&lt;/code&gt;, &lt;code&gt;removeToken&lt;/code&gt; and &lt;code&gt;setToken&lt;/code&gt; variables respectively.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;removeToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setToken&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, the &lt;code&gt;BrowserRouter&lt;/code&gt; function is made the parent component and in it, the &lt;code&gt;Header&lt;/code&gt; component is placed with the &lt;code&gt;removeToken&lt;/code&gt; function passed as an argument which is called &lt;code&gt;prop&lt;/code&gt; in react.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;removeToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the javascript conditional ternary operator is used to ensure that the user must have a token before having access to the &lt;code&gt;profile&lt;/code&gt; component. If the user doesn't have a token, the &lt;code&gt;Login&lt;/code&gt; component is rendered with the &lt;code&gt;setToken&lt;/code&gt; function passed as an argument. Else if the user already has a token, the &lt;code&gt;Profile&lt;/code&gt; component with the URL path &lt;code&gt;/profile&lt;/code&gt; is rendered and displayed to the user.&lt;/p&gt;

&lt;p&gt;You can read more on how to use &lt;code&gt;React Router&lt;/code&gt; &lt;a href="https://www.geeksforgeeks.org/reactjs-router/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you need to create the Login, Header, and Profile functions in your &lt;code&gt;Login&lt;/code&gt;, Header, and &lt;code&gt;Profile&lt;/code&gt; component files respectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Login.js
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loginForm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setloginForm&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;logMeIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
          &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;loginForm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;loginForm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;

      &lt;span class="nf"&gt;setloginForm&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;

      &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;
      &lt;span class="nf"&gt;setloginForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevNote&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;prevNote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;)}&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
                  &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                  &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loginForm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
                  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
                  &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
                  &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loginForm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
                  &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                  &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loginForm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
                  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
                  &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
                  &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loginForm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logMeIn&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Submit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The code above should be easy to understand, the summary of what it does is to use the login details provided by the user to make a &lt;code&gt;POST&lt;/code&gt; request to the &lt;code&gt;/token&lt;/code&gt; API endpoint in the backend which then returns the user's token and the token is stored in the local web storage using the &lt;code&gt;setToken&lt;/code&gt; function passed as a prop to the Login function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Header.js
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;logo&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../logo.svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;logMeOut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/logout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;token&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App-header&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App-logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logMeOut&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
                &lt;span class="nx"&gt;Logout&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/header&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Once the user clicks on the &lt;code&gt;Logout&lt;/code&gt; button, a &lt;code&gt;POST&lt;/code&gt; request is made to the &lt;code&gt;/logout&lt;/code&gt; API endpoint, and the cookies in which the user's JWToken is stored are cleared on the backend. The &lt;code&gt;Axios&lt;/code&gt; response function is used to call the &lt;code&gt;removeToken&lt;/code&gt; function which deletes the &lt;code&gt;token&lt;/code&gt; stored in the local web storage. Now, if the user tries to access the &lt;code&gt;/profile&lt;/code&gt; page, the user gets redirected to the login page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Profile.js
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;profileData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setProfileData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bearer &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;setProfileData&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;
        &lt;span class="na"&gt;profile_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;about_me&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;about&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;To&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt; &lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&amp;lt;button onClick={getData}&amp;gt;Click me&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;profileData&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Profile&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;profileData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;profile_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;About&lt;/span&gt; &lt;span class="na"&gt;me&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;profileData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;about_me&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Profile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The piece of code previously in &lt;code&gt;App.js&lt;/code&gt; was moved here. This contains the protected endpoint &lt;code&gt;\profile&lt;/code&gt;. A &lt;code&gt;GET&lt;/code&gt; request method is sent to the endpoint whenever the &lt;code&gt;Click me&lt;/code&gt; button is clicked and it responds with the user's details. &lt;/p&gt;

&lt;p&gt;For the user to be able to access the data of the &lt;code&gt;\profile&lt;/code&gt; API endpoint, an Authorization header that contains the token must be added to the axios &lt;code&gt;GET&lt;/code&gt; request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bearer &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the response contains an &lt;code&gt;access token&lt;/code&gt;, this means that the current token is near expiration and the server has created a new token. So the token stored in the local storage is updated with the newly generated token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  App.css
&lt;/h3&gt;

&lt;p&gt;You also need to make a change to the CSS style for the header. On line 16 you'll see the style for the header component &lt;code&gt;.App-header&lt;/code&gt;. Comment out or delete the &lt;code&gt;/* min-height: 100vh; */&lt;/code&gt; code so your application can end up looking like 👇:&lt;/p&gt;

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

&lt;p&gt;Now to test your application, start the backend server by running the script below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;followed by :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then navigate to the &lt;code&gt;http://localhost:3000/profile&lt;/code&gt; URL in your web browser and you'll be prompted to login since the page is protected. I hope you still remember the login details: &lt;code&gt;email:test&lt;/code&gt; and &lt;code&gt;password:test&lt;/code&gt;. You can also open up &lt;code&gt;localStorage&lt;/code&gt; under the &lt;code&gt;Application&lt;/code&gt; section in &lt;code&gt;Developer tools&lt;/code&gt; to monitor the token as it gets stored and deleted.&lt;/p&gt;

&lt;p&gt;It's been a long ride, but we have finally come to the end of this tutorial. With what you have learned, I believe you can easily authenticate your flask plus react applications. Congratulations on the new knowledge you just acquired.&lt;/p&gt;

&lt;p&gt;If you have any questions, feel free to drop them as a comment or send me a message on &lt;a href="https://www.linkedin.com/in/faruq-abdulsalam" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt; or &lt;a href="https://twitter.com/Ace_II" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and I'll ensure I respond as quickly as I can. Ciao 👋&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>python</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to connect Flask to ReactJs</title>
      <dc:creator>Faruq Abdulsalam</dc:creator>
      <pubDate>Tue, 14 Dec 2021 08:41:26 +0000</pubDate>
      <link>https://dev.to/nagatodev/how-to-connect-flask-to-reactjs-1k8i</link>
      <guid>https://dev.to/nagatodev/how-to-connect-flask-to-reactjs-1k8i</guid>
      <description>&lt;p&gt;Building web applications with the &lt;code&gt;Flask&lt;/code&gt; framework and the inbuilt &lt;a href="https://palletsprojects.com/p/jinja/" rel="noopener noreferrer"&gt;jinja&lt;/a&gt; template is cool but hooking your backend to a react frontend(which I believe we all love 😉) is much more interesting. In this tutorial, you are going to be taken through the easy steps you need to take to connect your &lt;code&gt;Flask&lt;/code&gt; backend to a &lt;code&gt;React&lt;/code&gt; frontend. &lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisite
&lt;/h2&gt;

&lt;p&gt;1) Beginner level understanding of the flask framework. If you are new to &lt;code&gt;Flask&lt;/code&gt; you can check out my article on how to set up your flask project and use it with the &lt;a href="https://palletsprojects.com/p/jinja/" rel="noopener noreferrer"&gt;jinja&lt;/a&gt; template engine &lt;a href="https://dev.to/nagatodev/getting-started-with-flask-1kn1"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;2) Familiarity with the basics of &lt;code&gt;ReactJs&lt;/code&gt;. You will be making use of the &lt;code&gt;useState&lt;/code&gt; hook and also fetching data from API using &lt;code&gt;axios&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project directory
&lt;/h2&gt;

&lt;p&gt;Create the project directory where your application will be stored and then navigate into it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mkdir&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cd&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  React frontend setup
&lt;/h2&gt;

&lt;p&gt;Create the frontend react application by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npx&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;react&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="nx"&gt;flask_react&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Move into the &lt;code&gt;flask_react&lt;/code&gt; directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cd&lt;/span&gt; &lt;span class="nx"&gt;flask_react&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then start the frontend application by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default react application page should pop up in your browser; if it does not, copy and open the link below in your browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  Flask backend setup
&lt;/h2&gt;

&lt;p&gt;Create a new directory in your base directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mkdir&lt;/span&gt; &lt;span class="nx"&gt;backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then navigate into it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cd&lt;/span&gt; &lt;span class="nx"&gt;backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have been following my &lt;code&gt;Building a web application with Flask&lt;/code&gt; series you should know the next thing that needs to be created. Yes, a virtual environment. Did you happen to get that right? 😀&lt;/p&gt;

&lt;h3&gt;
  
  
  Virtual environment
&lt;/h3&gt;

&lt;p&gt;It is recommended to always create a virtual environment before you start your project. This helps you to separate the packages you use in this application from other applications; any change you make here won't affect the same package in another application on your system. To create a  virtual environment on your system; run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;mac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;unix&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;python3&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="nx"&gt;venv&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;
&lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;windows&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;py&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="nx"&gt;venv&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating the environment, activate it by running :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;mac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;unix&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;activate&lt;/span&gt;
&lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;windows&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nx"&gt;Scripts&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nx"&gt;activate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Installing Flask
&lt;/h3&gt;

&lt;p&gt;Now that you have your environment up and running, you can go ahead and install Flask&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pip&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next thing is to register the script in an environment file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pip&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;dotenv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After successful installation, create the &lt;code&gt;.flaskenv&lt;/code&gt; file in the &lt;code&gt;backend&lt;/code&gt; directory created above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;touch&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flaskenv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please note that the preceding &lt;code&gt;.&lt;/code&gt; is very important. If you name your file just &lt;code&gt;flaskenv&lt;/code&gt;, any environment variable you'll put in it won't be read.&lt;/p&gt;

&lt;p&gt;Now put your environment variables in the &lt;code&gt;.flaskenv&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;FLASK_APP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;py&lt;/span&gt;
&lt;span class="nx"&gt;FLASK_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;development&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application environment is set to development mode so you can easily debug your application and the base.py file which will contain your flask application will be created in the next section.&lt;/p&gt;

&lt;p&gt;If the above approach is not used, you would need to keep on exporting your environment variables using &lt;code&gt;export FLASK_APP=base.py&lt;/code&gt; and &lt;code&gt;export FLASK_ENV=development&lt;/code&gt; whenever you restart your terminal window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; To ensure that the focus of this article doesn't deviate, I'll be making the flask backend structure simple. If you want to build bigger projects you definitely have to create a better folder structure for your application. You can check out my articles on &lt;a href="https://dev.to/nagatodev/getting-started-with-flask-1kn1"&gt;Getting started with Flask&lt;/a&gt; and &lt;a href="https://dev.to/nagatodev/building-a-todo-list-application-with-flask-fcj"&gt;Building a Todo List Application with Flask&lt;/a&gt; if you need to learn how to create a folder structure for larger projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  base.py
&lt;/h3&gt;

&lt;p&gt;Create a new file &lt;code&gt;base.py&lt;/code&gt; in the &lt;code&gt;backend&lt;/code&gt; directory where the &lt;code&gt;.flaskenv&lt;/code&gt; directory is also located.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;touch&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;py&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your folder structure should currently look like 👇&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxushvw3xnha5k71ns1h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxushvw3xnha5k71ns1h.png" alt="Folder structure" width="485" height="593"&gt;&lt;/a&gt;&lt;br&gt;
Inside the &lt;code&gt;base.py&lt;/code&gt; script create a simple API that returns your name and info about you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Flask&lt;/span&gt;

&lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_profile&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nx"&gt;response_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nagato&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;about&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello! I'm a full stack developer that loves python and javascript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response_body&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above contains a simple API which would be called by the react front end to get the &lt;code&gt;response_body&lt;/code&gt; dictionary.&lt;/p&gt;

&lt;p&gt;You might have noticed two things:&lt;br&gt;
i) the &lt;code&gt;GET&lt;/code&gt; http method is not specified here. This is because, by default, &lt;code&gt;view&lt;/code&gt; functions in flask accept GET requests only.&lt;br&gt;
ii) the &lt;code&gt;response_body&lt;/code&gt; dictionary being returned at the end of the function is not being passed as an argument to the popular &lt;code&gt;jsonify&lt;/code&gt; function like this &lt;code&gt;jsonify(response_body)&lt;/code&gt;. This is because view functions in Flask can return a dictionary, which Flask then turns to JSON format.&lt;/p&gt;

&lt;p&gt;The backend has been successfully set up, you can test this by running your application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then navigate to the url &lt;code&gt;http://127.0.0.1:5000/profile&lt;/code&gt;.You should see the dictionary &lt;code&gt;response_body&lt;/code&gt; rendered in JSON format.&lt;/p&gt;

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

&lt;p&gt;You could also use &lt;code&gt;postman&lt;/code&gt; to confirm this and you'll still get the same result.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jpcob7r7jot1qowyiio.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jpcob7r7jot1qowyiio.png" alt="postman-api-call" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to push your code to source control. Don't forget to add your &lt;code&gt;env&lt;/code&gt; and &lt;code&gt;__pycache__&lt;/code&gt; folders to the &lt;code&gt;gitignore&lt;/code&gt; file in the base directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;backend&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;
&lt;span class="nx"&gt;backend&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;__pycache__&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Connecting the API endpoint(/profile) to the react frontend
&lt;/h2&gt;

&lt;p&gt;Now you can return to the base directory where the react frontend is located.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cd&lt;/span&gt; &lt;span class="p"&gt;..&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install the &lt;code&gt;axios&lt;/code&gt; library:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You can choose to use either &lt;code&gt;axios&lt;/code&gt; or &lt;code&gt;fetch&lt;/code&gt; to make HTTP requests. However, in this article, the &lt;code&gt;axios&lt;/code&gt; library will be used to make requests to the API endpoints you built earlier on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  package.json
&lt;/h3&gt;

&lt;p&gt;Open the package.json file and add the proxy below the "private": true, line so it ends up like 👇.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flask_react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.1.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;private&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;proxy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:5000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//newline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By doing this, you will be able to use relative paths when you are making the API requests. Instead of making use of &lt;code&gt;http://localhost:5000/profile&lt;/code&gt; you can simply make use of &lt;code&gt;/profile&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The default url which is normally used to access flask applications in the browser is &lt;code&gt;http://127.0.0.1:5000&lt;/code&gt; but &lt;code&gt;http://localhost:5000&lt;/code&gt; was used above as the value to the proxy key. Don't be confused, they are both the same. You can read more on that &lt;a href="https://whatismyipaddress.com/localhost" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don't close the &lt;code&gt;package.json&lt;/code&gt; file yet. There is something cool you can add as well. You know that whenever your react server is started and you make any change in a file and you save it, the server restarts so that the new change can reflect right?. You can also add that feature to your flask backend application. This is another advantage of connecting react to flask 😎.&lt;/p&gt;

&lt;p&gt;Under the &lt;code&gt;scripts&lt;/code&gt; section add another key and value. &lt;br&gt;
&lt;code&gt;"start-backend": "cd backend &amp;amp;&amp;amp; env/bin/flask run --no-debugger",&lt;/code&gt; so it ends up looking like 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-scripts start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start-backend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cd backend &amp;amp;&amp;amp; env/bin/flask run --no-debugger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//new line&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-scripts build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-scripts test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eject&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-scripts eject&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can start your backend server with &lt;code&gt;npm run start-backend&lt;/code&gt;. This executes the command passed as its value in the package.json file. It navigates into the &lt;code&gt;env&lt;/code&gt; directory in your &lt;code&gt;backend&lt;/code&gt; directory and executes the &lt;code&gt;flask run&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;--no-debugger&lt;/code&gt; option is also passed here to disable the browser-based debugger as the Flask backend only serves as a server that holds the API endpoint.&lt;/p&gt;

&lt;h3&gt;
  
  
  app.js
&lt;/h3&gt;

&lt;p&gt;Here, you'll be making the call to the API endpoint in the flask backend server. After the changes, the app.js file will look exactly like 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;logo&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./logo.svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

   &lt;span class="c1"&gt;// new line start&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;profileData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setProfileData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;
      &lt;span class="nf"&gt;setProfileData&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;
        &lt;span class="na"&gt;profile_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;about_me&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;about&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})}&lt;/span&gt;
    &lt;span class="c1"&gt;//end of new line &lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App-header&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App-logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Edit&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/code&amp;gt; and save to reload&lt;/span&gt;&lt;span class="err"&gt;.
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;
          &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App-link&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://reactjs.org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_blank&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noopener noreferrer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Learn&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* new line start*/&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;To&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt; &lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&amp;lt;button onClick={getData}&amp;gt;Click me&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;profileData&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Profile&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;profileData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;profile_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;About&lt;/span&gt; &lt;span class="na"&gt;me&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;profileData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;about_me&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;}&lt;/span&gt;
         &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* end of new line */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/header&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now let's go through the new lines of code added to the app.js file.&lt;/p&gt;

&lt;p&gt;At the top of the file, the &lt;code&gt;useState&lt;/code&gt; hook and axios module are both imported.&lt;/p&gt;

&lt;p&gt;Then inside the function named &lt;code&gt;App&lt;/code&gt; the useState hook is used to control the state of the &lt;code&gt;profileData&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;getData&lt;/code&gt; function handles the API calls. It contains the &lt;code&gt;axios&lt;/code&gt; module which is used to send a &lt;code&gt;GET&lt;/code&gt; request to the API endpoint(\profile) on the backend which responds with the &lt;code&gt;jsonified&lt;/code&gt; format of the dictionary declared in the view function. &lt;/p&gt;

&lt;p&gt;Next, the &lt;code&gt;setProfileData&lt;/code&gt; function updates the state of &lt;code&gt;profileData&lt;/code&gt; by assigning the data in the json response to &lt;code&gt;profile_name&lt;/code&gt; and &lt;code&gt;about_me&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;getData&lt;/code&gt; function is only called when the &lt;code&gt;click me&lt;/code&gt; button is pressed.&lt;/p&gt;

&lt;p&gt;Finally &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; is used as a conditional operator, to avoid getting an error. &lt;code&gt;profileData&lt;/code&gt; is going to be assigned an initial &lt;code&gt;null&lt;/code&gt; state when the application first loads so if you try to access &lt;code&gt;profileData.profile_name&lt;/code&gt; or &lt;code&gt;profileData.about_me&lt;/code&gt; you get an error message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cannot&lt;/span&gt; &lt;span class="nx"&gt;read&lt;/span&gt; &lt;span class="nx"&gt;properties&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;null &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reading&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;profile_name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hence the need for the &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; conditional operator, so that the application only knows of the existence of the &lt;code&gt;profileData.profile_name&lt;/code&gt; and &lt;code&gt;profileData.about_me&lt;/code&gt; codes when the value of &lt;code&gt;profileData&lt;/code&gt; has changed from &lt;code&gt;null&lt;/code&gt; to containing the &lt;code&gt;response data&lt;/code&gt; from the API call.&lt;/p&gt;

&lt;p&gt;You don't need to make changes to any other file in the base directory. The work on the frontend part of the application is now complete. Now you can go ahead and test it:&lt;/p&gt;

&lt;p&gt;Step1: start your backend server using &lt;code&gt;npm run start-backend&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;note&lt;/strong&gt; this command can be run while you are in any directory; be it the base directory(flask_react) or the flask directory (backend)&lt;/p&gt;

&lt;p&gt;Step2: start your react server using &lt;code&gt;npm start&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;Now click on the &lt;code&gt;click me&lt;/code&gt; button to make the API call and get the &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;about_me&lt;/code&gt; data from the backend. &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh08hsk3ael2synu0viwc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh08hsk3ael2synu0viwc.png" alt="api call made to get name and about me data" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Voila!! you have successfully connected your flask backend to your react frontend. Now I am sure you can build small API endpoints in your flask backend and call the endpoints from your react frontend.&lt;/p&gt;

&lt;p&gt;If you have any questions, feel free to drop them as a comment or send me a message on &lt;a href="https://www.linkedin.com/in/faruq-abdulsalam" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt; or &lt;a href="https://twitter.com/Ace_II" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and I'll ensure I respond as quickly as I can.&lt;/p&gt;

&lt;p&gt;Incase you are a &lt;code&gt;Django&lt;/code&gt; lover, you would definitely love to connect it to &lt;code&gt;React&lt;/code&gt; as well. You can check out my article on &lt;a href="https://dev.to/nagatodev/how-to-connect-django-to-reactjs-1a71"&gt;How to connect Django to ReactJs&lt;/a&gt; to learn how to go about that. Ciao 👋&lt;/p&gt;

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

</description>
      <category>react</category>
      <category>webdev</category>
      <category>python</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Uploading media files to your Flask application</title>
      <dc:creator>Faruq Abdulsalam</dc:creator>
      <pubDate>Tue, 30 Nov 2021 09:30:32 +0000</pubDate>
      <link>https://dev.to/nagatodev/uploading-media-files-to-your-flask-application-5h9k</link>
      <guid>https://dev.to/nagatodev/uploading-media-files-to-your-flask-application-5h9k</guid>
      <description>&lt;p&gt;In this tutorial, you'll be taken through the easy steps required to upload a media file to your Flask applications. &lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisite
&lt;/h2&gt;

&lt;p&gt;We'll be building on the simple application built in part 1 of this series. I believe you can recreate that setup by yourself now. &lt;/p&gt;

&lt;p&gt;If you are new to the series, do well to check out part 1  before proceeding. Let's get started!!!&lt;/p&gt;

&lt;h2&gt;
  
  
  Configurations
&lt;/h2&gt;

&lt;p&gt;The first thing to do is to create the &lt;code&gt;Configuration&lt;/code&gt; class that will handle the following&lt;/p&gt;

&lt;p&gt;i) location where the uploaded files will be stored&lt;br&gt;
ii) secret key&lt;br&gt;
iii) allowed file extensions&lt;br&gt;
iv) limiting the size of the file that can be uploaded.&lt;/p&gt;
&lt;h3&gt;
  
  
  static/uploads directory
&lt;/h3&gt;

&lt;p&gt;Create a directory called &lt;code&gt;static&lt;/code&gt; in the &lt;code&gt;core&lt;/code&gt; directory. Then create an &lt;code&gt;uploads&lt;/code&gt; directory in the static directory. This is where your media files will be stored. You can choose to change the name of the directories if you choose to.&lt;/p&gt;
&lt;h3&gt;
  
  
  .env
&lt;/h3&gt;

&lt;p&gt;Since we'll be dealing with forms. We need to ensure that we provide our secret key as an environmental variable to ensure that the application doesn't become vulnerable through the form post requests.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in the root repository and place your secret key in it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;SECRET_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;put&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;your&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;own&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  config.py
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;config.py&lt;/code&gt; file in the base directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;load_dotenv&lt;/span&gt; 

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;basedir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abspath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nx"&gt;SECRET_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;UPLOAD_FOLDER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;core/static/uploads&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;ALLOWED_EXTENSIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jpeg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gif&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;MAX_CONTENT_LENGTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The secret key is loaded from the environment file &lt;code&gt;.env&lt;/code&gt; and assigned to the &lt;code&gt;SECRET_KEY&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;Next, the value assigned to the &lt;code&gt;UPLOAD_FOLDER&lt;/code&gt; variable is the path to the uploads folder created earlier on.  &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;allowed extensions&lt;/code&gt; coupled with the &lt;code&gt;maximum content length&lt;/code&gt;(size) of media files that can be uploaded are also specified here.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;init&lt;/strong&gt;.py
&lt;/h2&gt;

&lt;p&gt;Next, you need to import the Configuration class and configure the app variable with it. This assigns all the configuration settings to the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Flask&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;views&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  views.py
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;redirect&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;werkzeug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utils&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;secure_filename&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello there, Ace&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No file was selected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;elif&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;allowed_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nx"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;secure_filename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UPLOAD_FOLDER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="nf"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Image has been successfully uploaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Allowed media types are - png, jpg, jpeg, gif&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;allowed_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
           &lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rsplit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ALLOWED_EXTENSIONS&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Let's go through the code above:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;os&lt;/code&gt; module for path configuration, &lt;code&gt;Configuration&lt;/code&gt; class, and &lt;code&gt;flash&lt;/code&gt; function to display messages, &lt;code&gt;request method &amp;amp; redirect&lt;/code&gt; function to handle page redirects are all imported at the top of the file.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;secure_filename&lt;/code&gt; function is required to handle unclear or malicious file names. It ensures that the file names are always clean and flat.&lt;/p&gt;

&lt;p&gt;The default HTTP method is &lt;code&gt;GET&lt;/code&gt; so the &lt;code&gt;POST&lt;/code&gt; method needs to be added to the &lt;code&gt;app.route&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;After confirming that a POST request method was made, &lt;code&gt;request.files['file']&lt;/code&gt; is used to confirm that the data of a &lt;code&gt;file&lt;/code&gt; input with the name attribute of &lt;code&gt;file&lt;/code&gt; is included in the submitted form data and an error message is flashed if the condition evaluates to &lt;code&gt;false&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;The submitted data which is the uploaded media name + extension type is then passed as an argument to the &lt;code&gt;allowed_file&lt;/code&gt; function where it is split into &lt;code&gt;name of file&lt;/code&gt; and &lt;code&gt;extension&lt;/code&gt;. The &lt;code&gt;allowed_file&lt;/code&gt; function ensures that only a file with the permitted extension is processed and uploaded. &lt;/p&gt;

&lt;p&gt;Next, the &lt;code&gt;secure_filename&lt;/code&gt; function is called with the filename as an argument. It helps to ensure that a file with a malicious filename is not saved in the application.&lt;/p&gt;

&lt;p&gt;If all the checks are passed successfully, the uploaded media file is saved in the specified folder which in your case should be &lt;code&gt;static/uploads&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  index.html
&lt;/h2&gt;

&lt;p&gt;To test the file upload functionality, you need to make an upgrade to the index html page as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="nx"&gt;DOCTYPE&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Test&lt;/span&gt; &lt;span class="nx"&gt;HTML&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/title&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/head&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_flashed_messages&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flashes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endif&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endwith&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;enctype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;multipart&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;submit&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;Upload&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The newly added lines surrounded in curly braces allow the &lt;code&gt;flash&lt;/code&gt; messages to be rendered on the page in case an error occurs while uploading the file.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.w3schools.com/tags/att_form_enctype.asp" rel="noopener noreferrer"&gt;enctype&lt;/a&gt; attribute assigned the value&lt;br&gt;
&lt;code&gt;multipart/form-data&lt;/code&gt; is always used when files need to be uploaded via the form. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;file&lt;/code&gt; input has the name attribute, &lt;code&gt;file&lt;/code&gt; which the view function uses to confirm that a file was submitted together with the form.&lt;/p&gt;

&lt;p&gt;You can now run your application to test the whole setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll notice that when you try to submit the form without selecting an image, you get an error message notifying you that &lt;code&gt;No file was selected&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then when you finally do the right thing; and you upload an image, you get the message &lt;code&gt;Image has been successfully uploaded&lt;/code&gt;. Now go to the folder that was created in the static directory &lt;code&gt;core\static\uploads&lt;/code&gt;. You'll see the image file you just uploaded.&lt;/p&gt;

&lt;p&gt;Congratulations, we have come to the end of the tutorial. I believe you can now easily set up your flask applications to have file upload functionality. You can choose to make changes to the setup such as changing the allowed extensions, maximum content length, or the location of your uploads directory. Cheers!!&lt;/p&gt;

&lt;p&gt;Bonus: To use the image file, you can store the filename in your database after the image has been stored in the uploads folder, then Query the db for the filename and pass it to the render function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{{ url_for('static', filename=upload/'your filename') }}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the page is rendered, &lt;code&gt;your filename&lt;/code&gt; variable then gets replaced with the result of the db query for the stored &lt;code&gt;filename&lt;/code&gt; and, your image is displayed.&lt;/p&gt;

&lt;p&gt;If you have any questions, feel free to drop them as a comment or send me a message on &lt;a href="https://www.linkedin.com/in/faruq-abdulsalam" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt; or &lt;a href="https://twitter.com/Ace_II" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and I'll ensure I respond as quickly as I can. Ciao 👋&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Adding authentication to a Flask application</title>
      <dc:creator>Faruq Abdulsalam</dc:creator>
      <pubDate>Tue, 23 Nov 2021 09:38:54 +0000</pubDate>
      <link>https://dev.to/nagatodev/adding-authentication-to-a-flask-application-53ep</link>
      <guid>https://dev.to/nagatodev/adding-authentication-to-a-flask-application-53ep</guid>
      <description>&lt;p&gt;Welcome to the last part of the series. Here, you'll learn how to add authentication to your flask application. The todo application built in part 2 will be used here. So if you come across this part first, do well to check out parts 1 and 2. &lt;/p&gt;

&lt;p&gt;Let's get started!!&lt;/p&gt;

&lt;p&gt;Install the flask extension &lt;code&gt;Flask-login&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pip&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, open the&lt;code&gt;__init__.py&lt;/code&gt; file in the core directory. Import the &lt;code&gt;Login Manager&lt;/code&gt; class from the installed package and initialise the application with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Flask&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_sqlalchemy&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SQLAlchemy&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_migrate&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Migrate&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_login&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;LoginManager&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SQLAlchemy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;migrate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Migrate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoginManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  auth blueprint
&lt;/h2&gt;

&lt;p&gt;The authentication section will be created as a mini-application as well. So create a new directory &lt;code&gt;auth&lt;/code&gt; in the core directory and add the following files: &lt;code&gt;__init__.py&lt;/code&gt;, &lt;code&gt;forms.py&lt;/code&gt;, &lt;code&gt;models.py&lt;/code&gt;, and &lt;code&gt;views.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Remember that this is going to be an application on its own so you need to create a &lt;code&gt;templates&lt;/code&gt; folder in the auth directory as well. Create a new folder &lt;code&gt;auth&lt;/code&gt; in it and within it create two files &lt;code&gt;login.html&lt;/code&gt; and &lt;code&gt;register.html&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  auth blueprint
&lt;/h3&gt;

&lt;p&gt;Let's start with the &lt;code&gt;__init__.py&lt;/code&gt; script. This will be set up the same way as that of the &lt;code&gt;task&lt;/code&gt; blueprint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Blueprint&lt;/span&gt;

&lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Blueprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;template_folder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;templates&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;views&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  models.py
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;werkzeug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;security&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;generate_password_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;check_password_hash&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_login&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;UserMixin&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserMixin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nx"&gt;__tablename__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unique&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unique&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;password_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Todo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;backref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;author&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lazy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dynamic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;User {}&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_password_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;check_password_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;login&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user_loader&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then set up the User model for the database using the &lt;code&gt;UserMixin&lt;/code&gt; class. &lt;/p&gt;

&lt;p&gt;The todo field is initialized with &lt;code&gt;db.relationship&lt;/code&gt; which is like a &lt;code&gt;one-to-many&lt;/code&gt; relationship. The first argument &lt;code&gt;Todo&lt;/code&gt; passed here is the &lt;code&gt;many&lt;/code&gt; side of the relationship and the &lt;code&gt;one&lt;/code&gt; is &lt;code&gt;author&lt;/code&gt;. This will create an author field in every todo you create. &lt;/p&gt;

&lt;p&gt;The relationship established here just means that there will be &lt;code&gt;many&lt;/code&gt; posts linked to just &lt;code&gt;one&lt;/code&gt; user. This will ensure that one user doesn't have access to the to-do list of another user.&lt;/p&gt;

&lt;p&gt;The load_user function stores the id of the user so that the user can navigate to another page while logged in. If this is absent, whenever the user navigates to a new page, the user will be prompted to log in again.&lt;/p&gt;

&lt;h3&gt;
  
  
  forms.py
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_wtf&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;FlaskForm&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;wtforms&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;StringField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PasswordField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BooleanField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SubmitField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ValidationError&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;wtforms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validators&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;DataRequired&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;EqualTo&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FlaskForm&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StringField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;validators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;DataRequired&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                                       &lt;span class="nc"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
    &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PasswordField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;validators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;DataRequired&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
    &lt;span class="nx"&gt;remember_me&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BooleanField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Remember Me&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;submit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SubmitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sign In&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RegistrationForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FlaskForm&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StringField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;validators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;DataRequired&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
    &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StringField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;validators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;DataRequired&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
    &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PasswordField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;validators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;DataRequired&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
    &lt;span class="nx"&gt;password2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PasswordField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Repeat Password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;validators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;DataRequired&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;EqualTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
    &lt;span class="nx"&gt;submit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SubmitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Register&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_username&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nx"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Username already in use.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nx"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Email already registered.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;You need to install the package that'll validate the email address submitted by the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pip&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;email_validator&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the Login and Registration forms and import the &lt;code&gt;User&lt;/code&gt; model for validation purposes. This checks whether the email or username is already in the database and raises an error if a similar email or username is found.&lt;/p&gt;

&lt;h3&gt;
  
  
  views.py
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_login&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;login_user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logout_user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;login_required&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
    &lt;span class="nx"&gt;current_user&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forms&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;RegistrationForm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LoginForm&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;werkzeug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;urls&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;url_parse&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/register&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;is_authenticated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task.tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RegistrationForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validate_on_submit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Congratulations, you are now a registered user!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth.login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth/register.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Register&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nx"&gt;nologin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;is_authenticated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task.tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoginForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validate_on_submit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;check_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nx"&gt;nologin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;True&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;login_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remember&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remember_me&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;next_page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;next_page&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt; &lt;span class="nf"&gt;url_parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next_page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;netloc&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nx"&gt;next_page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task.tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth/login.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sign In&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;nologin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/logout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;logout_user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's go through each function:&lt;br&gt;
i) &lt;strong&gt;Register&lt;/strong&gt;: if the user navigates to the &lt;code&gt;\register&lt;/code&gt; URL, the register function is executed and the first condition provided checks if the user is already logged in. Then the user gets redirected to the index page of the application if this evaluates to &lt;code&gt;true&lt;/code&gt;. Else, the register page is loaded and the form is rendered. Upon submission, the form is validated and the user data is stored. Next, the user is redirected to the login page.&lt;br&gt;
ii)&lt;strong&gt;Login&lt;/strong&gt;: if the user navigates to the &lt;code&gt;\login&lt;/code&gt; URL, the login function is executed and a similar process is repeated here.&lt;br&gt;
iii)&lt;strong&gt;Logout&lt;/strong&gt;: When the user clicks on the logout button and is redirected to the &lt;code&gt;logout&lt;/code&gt; URL, the user gets logged out.&lt;/p&gt;

&lt;p&gt;The HTML template files are written in the same format as the other template files in parts 1 and 2 so they are self-explanatory&lt;/p&gt;
&lt;h3&gt;
  
  
  login.html
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;brand-logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{{ url_for('index') }}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{{ url_for('static', filename='Logo.svg') }}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;brand-logo-name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;strong&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ToDo&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/strong&amp;gt; &amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;Display&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alert alert-warning&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alert&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;closebtns&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onclick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;this.parentElement.style.display='none';&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;times&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&amp;gt;Invalid username or passwor&lt;/span&gt;&lt;span class="err"&gt;d
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endif&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;novalidate&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p-3 border border-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hidden_tag&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Login-Header&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h4&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mb-5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h4&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;color: red;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[{{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}}]&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;color: red;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[{{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}}]&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remember_me&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remember_me&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loginbtn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;btn btn-primary mt-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;logged_in&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Dont&lt;/span&gt; &lt;span class="nx"&gt;have&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt; &lt;span class="nx"&gt;yet&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{{ url_for('auth.register') }}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fa fa-hand-o-right&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;hidden&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/i&amp;gt;Register&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 

    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endblock&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;

&lt;h3&gt;
  
  
  register.html
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;brand-logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{{ url_for('index') }}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{{ url_for('static', filename='Logo.svg') }}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;brand-logo-name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;strong&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ToDo&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/strong&amp;gt; &amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;register&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p-3 border border-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hidden_tag&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Register-Header&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h4&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;has-text-centered mb-5 is-size-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Register&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h4&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;username&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;color: red;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[{{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}}]&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;color: red;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[{{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}}]&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;color: red;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[{{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}}]&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;password2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;color: red;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[{{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}}]&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;registerbtn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;btn btn-primary mt-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;registered&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Already&lt;/span&gt; &lt;span class="nx"&gt;registered&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{{ url_for('auth.login') }}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fa fa-hand-o-right&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;hidden&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/i&amp;gt;Login&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endblock&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;init&lt;/strong&gt;.py
&lt;/h3&gt;

&lt;p&gt;Finally, you need to register the &lt;code&gt;auth&lt;/code&gt; blueprint in the &lt;code&gt;__init__.py&lt;/code&gt; file in the core directory. Add the following lines of code above the &lt;code&gt;task&lt;/code&gt; blueprint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Flask&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Configuration&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_sqlalchemy&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SQLAlchemy&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_migrate&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Migrate&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_login&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;LoginManager&lt;/span&gt; 

&lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SQLAlchemy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;migrate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Migrate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoginManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login_view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth.login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;


&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;blueprint&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;our&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;blueprint&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;auth_blueprint&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register_blueprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auth_blueprint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;blueprint&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;non&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;authentication&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;task_blueprint&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register_blueprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task_blueprint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;views&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;models&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The path to the login view function is assigned to the initialised &lt;code&gt;LoginManager&lt;/code&gt; class and the &lt;code&gt;auth&lt;/code&gt; blueprint is registered with the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  models.py (base)
&lt;/h3&gt;

&lt;p&gt;Since you already established a relationship between the User model and Todo model. You need to head to the &lt;code&gt;models.py&lt;/code&gt; file in the core directory and create the &lt;code&gt;user_id&lt;/code&gt; field that'll be linked to the User model via a &lt;code&gt;ForeignKey&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the issue now is that SQLite database does not support dropping or altering columns. When you try to migrate and upgrade the db you get either a &lt;code&gt;naming convention&lt;/code&gt; or &lt;code&gt;ALTER of constraints&lt;/code&gt; error.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0dwk5840l92swxepafbg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0dwk5840l92swxepafbg.png" alt="ValueError" width="800" height="48"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  or
&lt;/h3&gt;

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

&lt;p&gt;There are two ways you can solve this.&lt;br&gt;
i) Delete the migrations folder and also the db file in your root directory. This is not advisable if you already have a lot of data in your db.&lt;br&gt;
ii) Create a naming convention for all your database columns in the &lt;code&gt;__init__.py&lt;/code&gt; file in the core directory. Solution can be found &lt;a href="https://github.com/ashishnitinpatil/udacity_fsnd004_item_catalog_application/commit/c0adae86653e5e92c6807e7c3f8eaa114a022b3c" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;init&lt;/strong&gt;.py
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Flask&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Configuration&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_sqlalchemy&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SQLAlchemy&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_migrate&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Migrate&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_login&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;LoginManager&lt;/span&gt; 
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;sqlalchemy&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MetaData&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SQLAlchemy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;
&lt;span class="nx"&gt;naming_convention&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ix&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ix_%(column_0_label)s&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;uq&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;uq_%(table_name)s_%(column_0_name)s&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ck&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ck_%(table_name)s_%(column_0_name)s&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pk_%(table_name)s&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SQLAlchemy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;MetaData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;naming_convention&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;naming_convention&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nx"&gt;migrate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Migrate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;render_as_batch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;
&lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoginManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login_view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth.login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;


&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;blueprint&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;our&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;auth_blueprint&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register_blueprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auth_blueprint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;blueprint&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;non&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;authentication&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;task_blueprint&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register_blueprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task_blueprint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;views&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;models&lt;/span&gt;

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

&lt;/div&gt;


&lt;p&gt;Now run the following commands: &lt;code&gt;flask db stamp head&lt;/code&gt;, &lt;code&gt;flask db migrate&lt;/code&gt; and &lt;code&gt;flask db upgrade&lt;/code&gt; to migrate all the changes to your db. The naming convention error should no longer exist.&lt;/p&gt;
&lt;h3&gt;
  
  
  views.py
&lt;/h3&gt;

&lt;p&gt;The final step is to make changes to the task view function so that users can only view the page if they are logged in. Make the following changes to the &lt;code&gt;views.py&lt;/code&gt; file in the task directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_login&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;login_required&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;current_user&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Category&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forms&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;TaskForm&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/create-task&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;login_required&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nx"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;current_user&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;
    &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;
    &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%Y-%m-%d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TaskForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;taskDelete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nx"&gt;deleteTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checkedbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;deleteTask&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deleteTask&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;one&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task.tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nx"&gt;check&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please check-box of task to be deleted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

        &lt;span class="nx"&gt;elif&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validate_on_submit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;
            &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;
            &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Congratulations, you just added a new note&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task.tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task/tasks.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Create Tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DateNow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;check&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Import the &lt;code&gt;login_required&lt;/code&gt; function and also the &lt;code&gt;current_user&lt;/code&gt; variable. Then assign the &lt;code&gt;login_required&lt;/code&gt; function as a decorator to the &lt;code&gt;task&lt;/code&gt; view function. The current logged in user is obtained via the current_user variable imported from the &lt;code&gt;flask_login&lt;/code&gt; package. &lt;/p&gt;

&lt;p&gt;The user variable is used to filter the &lt;code&gt;Todo List&lt;/code&gt; in the database for &lt;code&gt;todos&lt;/code&gt; created by the particular logged in user and it is also assigned to each todo created by the user.&lt;/p&gt;

&lt;p&gt;You can see the authentication feature that was just added in action by running the application. Try to navigate to the &lt;code&gt;\create-task&lt;/code&gt; and you'll get redirected to the login page. &lt;/p&gt;

&lt;p&gt;Register as a new user and log in to the application. Once you are successfully logged in, you'll automatically get redirected to the &lt;code&gt;create-task&lt;/code&gt; page. If you try to navigate to the &lt;code&gt;/login&lt;/code&gt; or &lt;code&gt;/register&lt;/code&gt; page while still logged in, you still get redirected to the &lt;code&gt;create-task&lt;/code&gt; page.&lt;/p&gt;

&lt;p&gt;You have successfully learnt how to add authentication to your application. With what you learnt in this series, you have all the ammunition required to build a great application now. &lt;/p&gt;

&lt;p&gt;If you want to add styling to your application to make it look like this 👇, &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7crb5wumfi6y35o0766g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7crb5wumfi6y35o0766g.png" alt="finished application" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
head to &lt;a href="https://github.com/Faruqt/Flask-Complete-Tutorial/tree/master" rel="noopener noreferrer"&gt;Github&lt;/a&gt;, clone the repository, and make the necessary changes to your static and template files. Good luck!!&lt;/p&gt;

&lt;p&gt;Congratulations!! We have come to the end of the journey. I hope you enjoyed the ride.&lt;/p&gt;

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

&lt;p&gt;If you have any questions, feel free to drop them as a comment or send me a message on &lt;a href="https://www.linkedin.com/in/faruq-abdulsalam" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt; or &lt;a href="https://twitter.com/Ace_II" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and I'll ensure I respond as quickly as I can. Ciao 👋&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a Todo List Application with Flask</title>
      <dc:creator>Faruq Abdulsalam</dc:creator>
      <pubDate>Tue, 23 Nov 2021 09:38:33 +0000</pubDate>
      <link>https://dev.to/nagatodev/building-a-todo-list-application-with-flask-fcj</link>
      <guid>https://dev.to/nagatodev/building-a-todo-list-application-with-flask-fcj</guid>
      <description>&lt;p&gt;In this part of the series, you'll learn how to build a web application with the &lt;code&gt;Flask&lt;/code&gt; framework. At the end of this part of the series, you'll have a working application with &lt;code&gt;create&lt;/code&gt;, &lt;code&gt;read&lt;/code&gt;, and &lt;code&gt;delete&lt;/code&gt; functionalities.&lt;/p&gt;

&lt;p&gt;Let's get started!!&lt;/p&gt;

&lt;h1&gt;
  
  
  Database Setup
&lt;/h1&gt;

&lt;p&gt;The database that will be used here is &lt;code&gt;sqlite&lt;/code&gt;, but you can choose any db of your choice.&lt;/p&gt;

&lt;p&gt;You'll need to install the &lt;a href="https://flask-sqlalchemy.palletsprojects.com/en/2.x/" rel="noopener noreferrer"&gt;Flask-SQLAlchemy&lt;/a&gt; and &lt;a href="https://github.com/miguelgrinberg/flask-migrate" rel="noopener noreferrer"&gt;Flask-Migrate&lt;/a&gt; extensions which will map all the data in your application to the &lt;code&gt;sqlite&lt;/code&gt; db and also handle database migrations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pip&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;sqlalchemy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pip&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;migrate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the root directory, create a &lt;code&gt;config.py&lt;/code&gt; and a &lt;code&gt;.env&lt;/code&gt; file where all the configurations for the application will be stored.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;touch&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;py&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;touch&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .env
&lt;/h3&gt;

&lt;p&gt;First, set up the .env file by adding your secret key here. Remember that it is bad practice to hardcode your &lt;code&gt;SECRET KEY&lt;/code&gt; in the main body of your application as this would make your application vulnerable to security breaches in production. That is why you need to always set it up as an environmental variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;SECRET_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;put&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;your&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;own&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Config.py
&lt;/h3&gt;

&lt;p&gt;Then add your configurations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;load_dotenv&lt;/span&gt; 

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;basedir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abspath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nx"&gt;SECRET_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;SQLALCHEMY_DATABASE_URI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sqlite:///&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;basedir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todo.db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;SQLALCHEMY_TRACK_MODIFICATIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here &lt;a href="https://docs.python.org/3/library/os.html" rel="noopener noreferrer"&gt;os&lt;/a&gt; is imported to handle the paths and also retrieve data from the environment. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;load_dotenv&lt;/code&gt; function is imported from the installed dotenv package and then called. This loads the &lt;code&gt;SECRET KEY&lt;/code&gt; variable stored in the &lt;code&gt;.env&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;basedir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abspath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The value assigned to the &lt;code&gt;basedir&lt;/code&gt; variable is the path for the root directory. This is done to avoid hardcoding the path to the root directory which may change whenever you make changes to the structure of your directories.&lt;/p&gt;

&lt;p&gt;Finally, the configuration settings are assigned to variables under the &lt;code&gt;Configuration&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;i) the value of the &lt;code&gt;SECRET KEY&lt;/code&gt; obtained when the &lt;code&gt;load_dotenv&lt;/code&gt; function is called and assigned to the &lt;code&gt;SECRET KEY&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;ii) the database URL is obtained from the environment file and assigned to the &lt;code&gt;SQLALCHEMY_DATABASE_URI&lt;/code&gt; variable. The &lt;code&gt;or&lt;/code&gt; operator is used here so that if the database URL is not specified in the &lt;code&gt;.env&lt;/code&gt; file, the variable &lt;code&gt;DATABASE URL&lt;/code&gt; is set to the base directory. &lt;code&gt;todo.db&lt;/code&gt; is the name of the database that'll be created in the root directory. You can choose to change the name of the db to whatever suits you.&lt;/p&gt;

&lt;p&gt;iii) &lt;code&gt;SQLALCHEMY_TRACK_MODIFICATIONS&lt;/code&gt; is set to false, this disables the feature which sends a signal every time the database changes.&lt;/p&gt;

&lt;p&gt;The database and configuration setup is done. Now, you need to register it in your &lt;strong&gt;init&lt;/strong&gt;.py script.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;init&lt;/strong&gt;.py
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Flask&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Configuration&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_sqlalchemy&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SQLAlchemy&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_migrate&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Migrate&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SQLAlchemy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;migrate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Migrate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;views&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;models&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Import the &lt;code&gt;Configuration&lt;/code&gt; class and configure the app variable with it. This assigns all the configuration settings to the application.&lt;/p&gt;

&lt;p&gt;Next, import &lt;code&gt;SQLAlchemy&lt;/code&gt; and &lt;code&gt;Migrate&lt;/code&gt; from the packages installed earlier and configure them as done above. &lt;/p&gt;

&lt;h3&gt;
  
  
  models.py
&lt;/h3&gt;

&lt;p&gt;You need to create a database module &lt;code&gt;models.py&lt;/code&gt; in your &lt;code&gt;core&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;140&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;category.id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;ToDo {}&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The db variable in the &lt;code&gt;__init__.py&lt;/code&gt; file is imported here and used to set up the structure(columns) of the database.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;id&lt;/code&gt; field is declared as an integer type and the database will assign the primary key automatically.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Todolist&lt;/code&gt; database model class will have &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, and &lt;code&gt;time&lt;/code&gt; fields as well so the &lt;code&gt;title&lt;/code&gt; field is declared as a string type, &lt;code&gt;date and time&lt;/code&gt; are declared as types date and time respectively.&lt;/p&gt;

&lt;p&gt;Each &lt;code&gt;todo&lt;/code&gt; created will also have a category, so you need to create a category field as type string. This will be connected to the &lt;code&gt;Category&lt;/code&gt; database model that will be created later on.&lt;/p&gt;

&lt;p&gt;The last line &lt;code&gt;def __repr__(self):&lt;/code&gt; defines the format in which python will print the objects of this database model.&lt;/p&gt;

&lt;h1&gt;
  
  
  Blueprints
&lt;/h1&gt;

&lt;p&gt;The application is about to grow massively, to prevent the project from becoming rough and confusing, and to ensure separation of concerns we'll be using &lt;a href="https://flask.palletsprojects.com/en/2.0.x/blueprints/#templates" rel="noopener noreferrer"&gt;Blueprints&lt;/a&gt;. Each part of the application will be made into modular applications which will all be registered in the &lt;code&gt;__init__.py&lt;/code&gt; file in the core directory.&lt;/p&gt;

&lt;p&gt;Let's start with the blueprint (mini-application) that will make it possible for the user to create &lt;code&gt;todos&lt;/code&gt;. Create a new directory &lt;code&gt;task&lt;/code&gt; in the core directory. Next, create the following files in the &lt;code&gt;task&lt;/code&gt; directory: &lt;code&gt;__init__.py&lt;/code&gt;, &lt;code&gt;forms.py&lt;/code&gt;, &lt;code&gt;models.py&lt;/code&gt;, and &lt;code&gt;views.py&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Remember that this is going to be an application on its own so you need to create a &lt;code&gt;templates&lt;/code&gt; folder in the &lt;code&gt;task&lt;/code&gt; directory as well. Create a new folder task in it and within it a file named &lt;code&gt;tasks.html&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  task blueprint
&lt;/h2&gt;

&lt;p&gt;Let's work on the &lt;strong&gt;init&lt;/strong&gt;.py script. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;init&lt;/strong&gt;.py
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Blueprint&lt;/span&gt;

&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Blueprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;template_folder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;templates&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;views&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Blueprint&lt;/code&gt; class is imported from the flask package and the name of the current blueprint &lt;code&gt;task&lt;/code&gt; is assigned to the constructor Blueprint(). The &lt;strong&gt;name&lt;/strong&gt; is passed as an argument as well, as discussed earlier python automatically passes the name of the base module &lt;code&gt;core&lt;/code&gt; here. Next, the folder in which the application will look for template files is assigned to the &lt;code&gt;template_folder&lt;/code&gt; variable and also passed as an argument to the blueprint constructor.&lt;/p&gt;

&lt;p&gt;Finally, the content of the &lt;code&gt;views.py&lt;/code&gt; file will be imported into the script so that they can all be registered with the blueprint.&lt;/p&gt;

&lt;h3&gt;
  
  
  models.py
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;Category {}&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;db&lt;/code&gt; variable is imported from the core directory  and used to set up the &lt;code&gt;Category&lt;/code&gt; database model class. This should be self-explanatory with the explanation done above when the &lt;code&gt;Todo&lt;/code&gt; model class was created.&lt;/p&gt;

&lt;h3&gt;
  
  
  forms.py
&lt;/h3&gt;

&lt;p&gt;To create the forms for the application you'll need to install Flask-WTF:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pip&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;wtf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you can create the various fields for the form that users will use to create todos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask_wtf&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;FlaskForm&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;wtforms&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;StringField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TimeField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DateField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SubmitField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SelectField&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;wtforms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validators&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;DataRequired&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;EqualTo&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TaskForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FlaskForm&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StringField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;validators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;DataRequired&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
    &lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SelectField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Category&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coerce&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;validators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;DataRequired&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
    &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DateField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;%Y-%m-%d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;validators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;DataRequired&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
    &lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TimeField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Time&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;%H:%M&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;validators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;DataRequired&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
    &lt;span class="nx"&gt;submit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SubmitField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Add task&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A label is the first variable assigned to each form field declared, &lt;code&gt;DataRequired&lt;/code&gt; is passed to the form validators as well to ensure that the fields are not left blank by the user.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;coerce&lt;/code&gt; keyword arg passed to the SelectField tells the application to use the int() function to coerce data for this particular field from the Task form.&lt;/p&gt;

&lt;h3&gt;
  
  
  views.py
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Category&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forms&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;TaskForm&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/create-task&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nx"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;
    &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%Y-%m-%d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TaskForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task/tasks.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Create Tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DateNow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;check&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;First, the required functions from flask, model classes, db, form, and datetime class are imported into the &lt;code&gt;views&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The variable &lt;code&gt;task&lt;/code&gt; is imported from the &lt;code&gt;__init__.py&lt;/code&gt; blueprint script and is then extended as shown below with &lt;code&gt;.route&lt;/code&gt; functions by mapping the URL and adding the HTTP methods which in this case are &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/create-task&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is used as a decorator for the &lt;code&gt;tasks&lt;/code&gt; function defined below. In part 1 of the series app.route was used but since the &lt;code&gt;task&lt;/code&gt; blueprint is being used here, you can simply use task.route since the blueprint will eventually be registered in the app.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;check&lt;/code&gt; variable initially assigned a value of &lt;code&gt;None&lt;/code&gt; is simply used to pass an error message to the template. Next, the &lt;code&gt;Todo&lt;/code&gt; table in the database is queried for all the &lt;code&gt;todos&lt;/code&gt; in the database. This would later be changed when the &lt;code&gt;authentication&lt;/code&gt; blueprint is set up. The present date is obtained and formatted using the &lt;code&gt;strftime&lt;/code&gt; function. &lt;/p&gt;

&lt;p&gt;Finally, the view uses &lt;code&gt;render_template&lt;/code&gt; function to render the &lt;code&gt;tasks.html&lt;/code&gt; file in the tasks directory located in the templates directory. The function also takes the &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;form&lt;/code&gt;, &lt;code&gt;DateNow&lt;/code&gt;, and &lt;code&gt;check&lt;/code&gt; arguments that it will use to replace the placeholder variables that will be added to the &lt;code&gt;task&lt;/code&gt; html file.&lt;/p&gt;

&lt;p&gt;The choices for the select field are assigned the result of querying the &lt;code&gt;Category&lt;/code&gt; table in the database. Let's test the application before adding the conditions that will handle the methods. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;init&lt;/strong&gt;.py
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;task&lt;/code&gt; blueprint needs to be registered with the application so its content can also be recognized when the application is being run. Open the &lt;code&gt;__init__.py&lt;/code&gt; script in the core directory and add the following lines before the last import line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;blueprint&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;non&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;authentication&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;task_blueprint&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register_blueprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task_blueprint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;task&lt;/code&gt; variable to which the blueprint is assigned is imported from the &lt;code&gt;task&lt;/code&gt; directory as &lt;code&gt;task_blueprint&lt;/code&gt; and then registered with the application using the Flask inbuilt &lt;code&gt;register_blueprint&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Now you have to migrate the new database models to the database; you'll notice two new additions to your directory after doing this.&lt;/p&gt;

&lt;p&gt;i) a new folder named &lt;code&gt;migrations&lt;/code&gt; will be added to your root directory.&lt;/p&gt;

&lt;p&gt;ii) a new database will also be created in your root directory bearing whatever name you specified in your config file. If you remember, the name of the db was specified as &lt;code&gt;todo.db&lt;/code&gt; earlier on. If you made any change to yours, the database that will be created will bear the name you specified as well. Now let's see this in action. Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the new folder &lt;code&gt;migrations&lt;/code&gt; added to your root directory. Next, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="nx"&gt;migrate&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Put any comment of your choice here&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should see the created database &lt;code&gt;todo.db&lt;/code&gt; in your root directory as well.&lt;/p&gt;

&lt;p&gt;The last command to run is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="nx"&gt;upgrade&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will apply all the changes you made to the database model class to your database. Your directory should currently look like 👇. &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F417qih4ilo1wwqnrn8ls.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F417qih4ilo1wwqnrn8ls.png" alt="Directory look" width="686" height="1090"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The category table in the database is currently empty so let's go ahead and create the three categories that the user can choose when creating their &lt;code&gt;todo list&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  python shell
&lt;/h3&gt;

&lt;p&gt;Open up the python shell in your terminal using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;python&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, import the Category model from the task directory in the core directory and the db as well&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Category&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the three categories&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ctgry1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Business&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;ctgry2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Personal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;ctgry3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Other&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the variables need to be added to the current database session using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctgry1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctgry2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctgry3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the session is committed so that the changes  are applied to the Category table in the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To confirm that the categories &lt;code&gt;Business&lt;/code&gt;, &lt;code&gt;Personal&lt;/code&gt;, and &lt;code&gt;Other&lt;/code&gt; have all been added to the &lt;code&gt;Category&lt;/code&gt; table in the database, run the commands below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The categories should be printed out exactly like what is in the image below.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkx33qncvlsi7xijdq68q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkx33qncvlsi7xijdq68q.png" alt="Categories List" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before you can go ahead and run the application, you need to create the HTML code that will be rendered by the &lt;code&gt;task&lt;/code&gt; view function. &lt;br&gt;
First you need to create a base html file and then set up the &lt;code&gt;task&lt;/code&gt; html file as an extension of the base file.&lt;/p&gt;
&lt;h3&gt;
  
  
  base.html
&lt;/h3&gt;

&lt;p&gt;Create a new file named &lt;code&gt;base.html&lt;/code&gt; inside the &lt;code&gt;templates&lt;/code&gt; directory in the &lt;code&gt;core&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="nx"&gt;doctype&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/title&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Todo&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/title&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endif&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/head&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endblock&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are new to jinja2 templates, the curly braces might look odd. The variable declared in the curly braces gets passed the value assigned to the variable when the &lt;code&gt;render_template&lt;/code&gt; function is called in the view. For example, &lt;code&gt;Create Tasks&lt;/code&gt; has already been assigned to the title variable so whenever the &lt;code&gt;render_template&lt;/code&gt; function is executed, &lt;code&gt;{{title}}&lt;/code&gt; in the &lt;code&gt;tasks.html&lt;/code&gt; file gets replaced with &lt;code&gt;Create Tasks&lt;/code&gt;. In jinja templates you can also make use of conditions such as &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;for&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Every other html file in the application will be an extension of this &lt;code&gt;base.html&lt;/code&gt; file and their contents will be filled into &lt;code&gt;{% block content %} {% endblock content%}&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  tasks.html
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;task_content categories&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;    
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;welcome&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openbutton&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openbtn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;9776&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;welcome-text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Manage&lt;/span&gt; &lt;span class="nx"&gt;Your&lt;/span&gt; &lt;span class="nx"&gt;ToDo&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;novalidate&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hidden_tag&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inputContainer Task&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;color: red;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[{{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}}]&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inputContainer choice &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;color: red;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[{{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}}]&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inputContainer  date &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;color: red;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[{{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}}]&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inputContainer  time&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;color: red;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[{{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}}]&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;buttons&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;   
                    &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;taskAdd btn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;Task&lt;/span&gt; &lt;span class="nx"&gt;Delete&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="nx"&gt;alert&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;check&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alert alert-warning&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alert&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;closebtns&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onclick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;this.parentElement.style.display='none';&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;times&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                    &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;check&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endif&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;End&lt;/span&gt; &lt;span class="nx"&gt;Task&lt;/span&gt; &lt;span class="nx"&gt;Delete&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="nx"&gt;alert&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;

            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hidden_tag&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;csrf&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;security&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;

              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tabs effect-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                 &lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tab-content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;section&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tab-item-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;taskList&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;        
                          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
                          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;currentTaskItem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;checkbox&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;taskCheckbox&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;checkedbox&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{{ todo.id }}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{{ todo.id }}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{{ todo.id }}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;complete-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;taskDone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;at&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;strong&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;taskDone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fa fa-clock-o&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/i&amp;gt; {{ todo.time }}&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;strong&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;taskDone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;strong&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;taskDatee taskDone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fa fa-calendar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/i&amp;gt; {{ todo.date }}&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;strong&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;categorypage-{{ todo.category }}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;taskDelete &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;taskDelete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;formnovalidate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fa fa-trash-o icon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/i&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&amp;gt;    &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;                          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&amp;gt; &amp;lt;!--end All-Tasks-List --&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/section&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&amp;lt;!-- end tab content --&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&amp;lt;!-- end tab effect --&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&amp;lt;!-- end content --&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&amp;lt;!-- container --&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endblock&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;form.hidden_tag()&lt;/code&gt; gets the &lt;code&gt;csrf token&lt;/code&gt; which protects the form against cross site request forgery(csrf) attacks.&lt;/p&gt;

&lt;p&gt;In the first form in the HTML file, the labels set when creating the &lt;code&gt;TaskForm&lt;/code&gt; e.g &lt;code&gt;{{ form.title.label }}&lt;/code&gt; are used as the labels for the input elements. While the input elements are created using the fields created in the form e.g &lt;code&gt;{{ form.title(size=20) }}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;size=20&lt;/code&gt; argument is an example of how to pass classes/attributes to the form field inputs. This sets the width of the input field to 20. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;if check&lt;/code&gt; line confirms if an error message exists and then renders the error alert elements if it does. Otherwise, no error message is displayed. &lt;/p&gt;

&lt;p&gt;In the second form, you first need to confirm that a  &lt;code&gt;todo&lt;/code&gt; list exists from the database query made in the view. Then, the result is looped through to get the &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;time&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, and &lt;code&gt;category&lt;/code&gt; variables and displayed as &lt;code&gt;li&lt;/code&gt; elements accordingly. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;action&lt;/code&gt; attributes in the forms are left blank because they'll both be sending form data to the page url.  &lt;/p&gt;

&lt;p&gt;Now let's see what has been built so far in the web browser. Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your web browser should still be displaying &lt;code&gt;Hello there, Ace&lt;/code&gt;. Navigate to &lt;code&gt;http://127.0.0.1:5000/create-task&lt;/code&gt; and you'll see the page below.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fue5ijhwvv6m9g8d3hl3z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fue5ijhwvv6m9g8d3hl3z.png" alt="Task creation page" width="732" height="885"&gt;&lt;/a&gt;&lt;br&gt;
Note that the title of the webpage was updated to what was specified in the render template function; &lt;code&gt;title='Create Tasks'&lt;/code&gt; and the form was rendered as a normal form even though you didn't exactly create form inputs in the HTML file. Flask-WTF handles this for you.&lt;/p&gt;

&lt;p&gt;Now, let's finish up the &lt;code&gt;task&lt;/code&gt; view so that it can handle &lt;code&gt;POST&lt;/code&gt; data from the front end. Add the following conditions to the &lt;code&gt;task&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;taskDelete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nx"&gt;deleteTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checkedbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;deleteTask&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deleteTask&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;one&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task.tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nx"&gt;check&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please check-box of task to be deleted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

        &lt;span class="nx"&gt;elif&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validate_on_submit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;
            &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task.tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the logic here will only be run if the method is a &lt;code&gt;POST&lt;/code&gt; request. Otherwise, the empty form will be rendered once again without any data. The &lt;code&gt;if&lt;/code&gt; condition contains two further conditions to check whether the user wants to delete or create a todo.&lt;/p&gt;

&lt;p&gt;Each &lt;code&gt;todo&lt;/code&gt; will be rendered as a form with a delete button attached to it so if a &lt;code&gt;post&lt;/code&gt; request is made the first condition checks if it was one of the delete forms that was submitted using the name attribute &lt;code&gt;taskDelete&lt;/code&gt; of the delete form's submit button specified in the task template file. &lt;/p&gt;

&lt;p&gt;If the condition passes, the next condition confirms that the checkbox was also checked before the &lt;code&gt;Todo&lt;/code&gt; table in the database is queried by filtering with the &lt;code&gt;id&lt;/code&gt; of the particular todo whose delete button was clicked. &lt;code&gt;.one()&lt;/code&gt; at the end of the query, limits the number of rows returned from the database to one and that would be only the todo with the specified &lt;code&gt;id&lt;/code&gt;. If the checkbox was not checked before the submit(Delete button) was pressed, an error message is displayed notifying the user that it needs to be checked before the todo can be deleted.&lt;/p&gt;

&lt;p&gt;Then just like you did when the &lt;code&gt;categories&lt;/code&gt; were created in the python shell, you also need to pass the &lt;code&gt;todo&lt;/code&gt; object obtained from the database to the session and then commit it so that the changes will be applied to the database. After this is done, the page is made to refresh with the redirect function by passing the same view function &lt;code&gt;tasks&lt;/code&gt; as an argument. &lt;code&gt;task.tasks&lt;/code&gt; is used here since you are working in the &lt;code&gt;task&lt;/code&gt; blueprint and this lets the application know the path to the task view. &lt;/p&gt;

&lt;p&gt;However if the first condition evaluates to false, the second condition is executed and the form data is extracted after the data submitted by the user has been validated. The selected category comes back as an integer value(the id) not a string since the coerce argument was set to int() for the &lt;code&gt;selectField&lt;/code&gt; in the forms.py file. The &lt;code&gt;id&lt;/code&gt; value is then used to query the &lt;code&gt;Category&lt;/code&gt; table in the database to get its matching &lt;code&gt;Category&lt;/code&gt; in the db. Next, all the data passed from the form is used to generate the object passed to the &lt;code&gt;todo&lt;/code&gt; variable, passed to the session, and finally committed to the database for storage. Thus, creating a new todo in the database. When this is completed, the page is made to refresh as well with the redirect function by passing the same view function &lt;code&gt;tasks&lt;/code&gt; as an argument.&lt;/p&gt;

&lt;p&gt;Your &lt;code&gt;task&lt;/code&gt; function should look exactly like 👇&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2mflc0t92w0w7im59ol.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2mflc0t92w0w7im59ol.png" alt="Task function view" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The create and delete functions have been created so you can put them to test now. Run your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fill the task form and click on the &lt;code&gt;Add Task&lt;/code&gt; button. Upon submission you'll notice that the web page reloads, the form is reset to default and your new task gets displayed.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7w6pb3zu0alsddv1j05a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7w6pb3zu0alsddv1j05a.png" alt="Task created" width="800" height="599"&gt;&lt;/a&gt;&lt;br&gt;
The button circled in red in the picture above is the delete button, click on it to delete the created todo. You'll get the error message specified in the &lt;code&gt;task&lt;/code&gt; view which is to notify the user that the checkbox needs to be checked. This helps to introduce a form of control for the delete button, making it impossible for the user to delete a created &lt;code&gt;todo&lt;/code&gt; by mistake. Check the box of the todo and click on the delete button once again. Now you'll notice that the todo gets deleted.&lt;/p&gt;

&lt;p&gt;Congratulations!! You have successfully created your first &lt;code&gt;FLASK&lt;/code&gt; application with create, read, and delete features. This is the end of part 2 of the &lt;code&gt;Flask&lt;/code&gt; series. &lt;code&gt;Authentication&lt;/code&gt; will be added to the application in part 3. Cheers!!!&lt;/p&gt;

&lt;p&gt;If you have any questions, feel free to drop them as a comment or send me a message on &lt;a href="https://www.linkedin.com/in/faruq-abdulsalam" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt; or &lt;a href="https://twitter.com/Ace_II" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and I'll ensure I respond as quickly as I can. Ciao 👋&lt;/p&gt;

</description>
      <category>python</category>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Getting started with Flask</title>
      <dc:creator>Faruq Abdulsalam</dc:creator>
      <pubDate>Sat, 20 Nov 2021 08:26:08 +0000</pubDate>
      <link>https://dev.to/nagatodev/getting-started-with-flask-1kn1</link>
      <guid>https://dev.to/nagatodev/getting-started-with-flask-1kn1</guid>
      <description>&lt;p&gt;Hello there, welcome to the &lt;code&gt;Flask&lt;/code&gt; world. In this series, you are going to learn how to build a web application using the micro web python framework &lt;code&gt;Flask&lt;/code&gt;. Let's get started!&lt;/p&gt;

&lt;p&gt;The code for this series has been made available on Github. However, I strongly advise you to follow the tutorial and create the application with what you will learn here rather than cloning the repo straightaway. You can then choose to access the repo at the end. &lt;/p&gt;

&lt;p&gt;The Github repo can be accessed via this &lt;a href="https://github.com/Faruqt/Flask-Complete-Tutorial/tree/master" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this part of the series, you are going to learn how to set up your Flask project and display a simple message in your browser. Let's get started.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setup
&lt;/h1&gt;

&lt;p&gt;I’ll assume that you already have python installed on your machine. If you don't, you can download and set it up via this &lt;a href="https://www.python.org/downloads/" rel="noopener noreferrer"&gt;link&lt;/a&gt;. Please ensure you download the latest version of python. (Python 3.97)&lt;/p&gt;

&lt;p&gt;Open the Command Line on Windows, Terminal on Mac, and Linux and navigate to the directory where you want to store the project and create a new directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mkdir&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Move into the new directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cd&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a Virtual environment.
&lt;/h3&gt;

&lt;p&gt;It is recommended to always create a virtual environment before you start your project. This helps you to separate the packages you use in this application from other applications; any change you make here won't affect the same package in another application on your system. To create a virtual environment on your system; run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;mac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;unix&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;python3&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="nx"&gt;venv&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;
&lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;windows&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;py&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="nx"&gt;venv&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating the environment, activate it by running :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;mac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;unix&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;activate&lt;/span&gt;
&lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;windows&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nx"&gt;Scripts&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nx"&gt;activate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can deactivate it by simply running the command below, but you don't have to deactivate it yet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;deactivate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Installing Flask
&lt;/h3&gt;

&lt;p&gt;First you have to install Flask,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pip&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are officially done with setting up your system for the flask project 🤝, now let us proceed to the project setup itself. &lt;/p&gt;

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

&lt;p&gt;Create a new directory inside the flask directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mkdir&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Move into the new directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cd&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next create two new files &lt;code&gt;__init__.py&lt;/code&gt; and &lt;code&gt;views.py&lt;/code&gt; with the commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;touch&lt;/span&gt; &lt;span class="nx"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;py&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;touch&lt;/span&gt; &lt;span class="nx"&gt;views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;py&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;init&lt;/strong&gt;.py
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Flask&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;views&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the created script, the &lt;code&gt;Flask&lt;/code&gt; class is imported from the installed flask package, and a &lt;code&gt;__name__&lt;/code&gt; variable is passed to it and they are finally assigned to an &lt;code&gt;app&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;__name__&lt;/code&gt; variable which is automatically set by python helps to get the name/location of the module in which the &lt;code&gt;__init__.py&lt;/code&gt; script is called. In this case, &lt;code&gt;__name__&lt;/code&gt; is &lt;code&gt;core&lt;/code&gt; because the script file &lt;code&gt;__init__.py&lt;/code&gt; is located in the &lt;code&gt;core&lt;/code&gt; directory and this tells Flask where to look for resources such as templates and static files. You will understand this better when the application starts becoming large and new packages are created to separate concerns.&lt;/p&gt;

&lt;p&gt;Finally, the &lt;code&gt;views.py&lt;/code&gt; module is imported from the project directory into the script. You must have noticed that the import is done at the bottom of the file, not at the top. The reason for this is to prevent the issue of circular imports. The routes module is being imported into the script but you will also need to import the app variable in the &lt;code&gt;views.py&lt;/code&gt; module which might lead to an error due to cyclical dependencies.&lt;/p&gt;

&lt;h4&gt;
  
  
  views.py
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello Ace&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;app&lt;/code&gt; variable declared in the &lt;code&gt;__init__.py&lt;/code&gt; script is imported here and used as a decorator. The line &lt;code&gt;@app.route('/')&lt;/code&gt; is a python decorator made available by flask and this is used to modify the index function called below it and to assign the URL "/" to the function. Thus, the index function gets executed whenever a user navigates to the specified URL mapped to it.&lt;/p&gt;

&lt;h4&gt;
  
  
  base.py
&lt;/h4&gt;

&lt;p&gt;To finish up, return to the root directory &lt;code&gt;flask&lt;/code&gt; and create a &lt;code&gt;base.py&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cd&lt;/span&gt; &lt;span class="p"&gt;..&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;touch&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;py&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and import the app variable into the script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  running the application
&lt;/h4&gt;

&lt;p&gt;To run the application, you need to export the script in the root directory &lt;code&gt;base.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;FLASK_APP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;py&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to the URL &lt;code&gt;http://127.0.0.1:5000/&lt;/code&gt; in your web browser and the page below should be displayed.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnqzhipiqp3dg8aiswqmi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnqzhipiqp3dg8aiswqmi.png" alt="Index function page" width="798" height="812"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To run the flask application whenever you open up a new terminal, you have to always export the script in the root directory. The solution to this is to create an environment to store the assignment of the script to the &lt;code&gt;FLASK_APP&lt;/code&gt;. To do this you need to install the python-dotenv package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pip&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;dotenv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a &lt;code&gt;.flaskenv&lt;/code&gt; file in the root directory and store the assignment of the script to the &lt;code&gt;FLASK_APP&lt;/code&gt; in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;touch&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flaskenv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;FLASK_APP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;py&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Please dont forget the '.' infront of flaskenv. If you do, this process won't work.&lt;/p&gt;

&lt;p&gt;Now, whenever you open a new terminal, you can just go ahead and run the application with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: To run the application without getting any error.You need to always be in the root directory before running the command &lt;code&gt;flask run&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The project setup is done, this should be the current look of your directory.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3iz100adf0oefbectnle.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3iz100adf0oefbectnle.png" alt="Current directory" width="583" height="437"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Templates
&lt;/h1&gt;

&lt;p&gt;Flask uses &lt;a href="https://flask.palletsprojects.com/en/2.0.x/templating/" rel="noopener noreferrer"&gt;jinja2&lt;/a&gt; template format by default.&lt;/p&gt;
&lt;h3&gt;
  
  
  index.html
&lt;/h3&gt;

&lt;p&gt;Create a folder named &lt;code&gt;templates&lt;/code&gt; in the core directory and create a file named index.html in it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cd&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mkdir&lt;/span&gt; &lt;span class="nx"&gt;templates&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cd&lt;/span&gt; &lt;span class="nx"&gt;templates&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;touch&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and put these basic lines of code in your HTML file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="nx"&gt;DOCTYPE&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Test&lt;/span&gt; &lt;span class="nx"&gt;HTML&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/title&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/head&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, a value will be assigned to the &lt;code&gt;greet&lt;/code&gt; variable included in the h1 element whenever the index.html file is being rendered. This will be explained better below.&lt;/p&gt;

&lt;h3&gt;
  
  
  views.py
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;render_template&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello there, Ace&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, some changes will be made to the &lt;code&gt;views.py&lt;/code&gt; file. You have to import the &lt;code&gt;render_template&lt;/code&gt; function from the flask package. The function renders the template file &lt;code&gt;index.html&lt;/code&gt; and assigns the value of the greeting variable to the &lt;code&gt;greet&lt;/code&gt; variable in the HTML file. &lt;/p&gt;

&lt;p&gt;You can test this by running the application with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flask&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open your web browser and navigate to the same URL as before &lt;code&gt;http://127.0.0.1:5000/&lt;/code&gt;. You should see your h1 element with the value of the variable &lt;code&gt;greeting&lt;/code&gt; declared in &lt;code&gt;views.py&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9azrt11hk2zd3ngc2c8b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9azrt11hk2zd3ngc2c8b.png" alt="End of series" width="800" height="813"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have finally come to the end of the first part of the series. With the simple examples given above, I am sure you can easily set up a new flask application for your project and also pass data from the backend to template files. &lt;/p&gt;

&lt;p&gt;In the next part of the series, we'll start creating our web application. Things will start getting complex but I'll make sure I break it down as much as I can. See you there!! Cheers!!!&lt;/p&gt;

&lt;p&gt;If you have any questions, feel free to drop them as a comment or send me a message on &lt;a href="https://www.linkedin.com/in/faruq-abdulsalam" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt; or &lt;a href="https://twitter.com/Ace_II" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and I'll ensure I respond as quickly as I can. Ciao 👋&lt;/p&gt;

</description>
      <category>python</category>
      <category>webdev</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
