<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Aglili Selorm Cecil</title>
    <description>The latest articles on Forem by Aglili Selorm Cecil (@aglili).</description>
    <link>https://forem.com/aglili</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%2F1399036%2F7ee24f4f-7020-45c0-96fc-9785715d6952.png</url>
      <title>Forem: Aglili Selorm Cecil</title>
      <link>https://forem.com/aglili</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/aglili"/>
    <language>en</language>
    <item>
      <title>Fastapi from localhost to production (part 1)</title>
      <dc:creator>Aglili Selorm Cecil</dc:creator>
      <pubDate>Wed, 16 Apr 2025 12:38:54 +0000</pubDate>
      <link>https://forem.com/aglili/fastapi-from-localhost-to-production-part-1-36nl</link>
      <guid>https://forem.com/aglili/fastapi-from-localhost-to-production-part-1-36nl</guid>
      <description>&lt;h2&gt;
  
  
  Deploying FastAPI to a VPS: Part 1 - Building and Dockerizing
&lt;/h2&gt;

&lt;p&gt;I'm starting this series to walk through how I deploy my FastAPI apps to a VPS. Getting stuff from your local machine to a live server can be a bit of a headache, so I figured I'd document my process using the tools I've found work best.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools I'm using:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FastAPI:&lt;/strong&gt; My go-to Python framework &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker:&lt;/strong&gt; Because you have to know it😂&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker Compose:&lt;/strong&gt; We'll use this in part 2 to manage multiple containers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gunicorn:&lt;/strong&gt; The production server for Python apps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uvicorn:&lt;/strong&gt; Needed for FastAPI's async magic, but we'll run it under Gunicorn's supervision&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What we're covering in Part 1:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setting up a basic FastAPI app&lt;/li&gt;
&lt;li&gt;Testing locally with Gunicorn (the way we'll run it in production)&lt;/li&gt;
&lt;li&gt;Dockerizing everything with multi-stage builds to keep our images small&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 1: Project Setup and Environment
&lt;/h3&gt;

&lt;p&gt;First, let's get our project structure and virtual environment going:&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;# Create the project directory&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;fast-microservice

&lt;span class="c"&gt;# Navigate into the new directory&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;fast-microservice

&lt;span class="c"&gt;# Create a Python virtual environment&lt;/span&gt;
&lt;span class="c"&gt;# (Use python3 -m venv venv if virtualenv command is not available)&lt;/span&gt;
virtualenv venv

&lt;span class="c"&gt;# Activate the virtual environment&lt;/span&gt;
&lt;span class="c"&gt;# On Windows use: .\venv\Scripts\activate&lt;/span&gt;
&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Install Dependencies
&lt;/h3&gt;

&lt;p&gt;We need a few packages to get started:&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;# Install necessary Python packages&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;fastapi &lt;span class="s2"&gt;"uvicorn[standard]"&lt;/span&gt; gunicorn pydantic

&lt;span class="c"&gt;# Freeze the installed packages and versions into requirements.txt&lt;/span&gt;
pip freeze &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Create the FastAPI Application
&lt;/h3&gt;

&lt;p&gt;Let's create our main app file:&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;main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the code for our basic user management API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;HTTPException&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi.middleware.cors&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi.responses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;JSONResponse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt; 

&lt;span class="c1"&gt;# Configure logging
&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fast Microservice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A simple FastAPI microservice for user management&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

&lt;span class="c1"&gt;# Use a separate model for output data (includes the ID)
&lt;/span&gt;&lt;span class="k"&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="n"&gt;UserCreate&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;

&lt;span class="c1"&gt;# --- In-Memory Storage ---
# A simple list to act as our database for this example
# In a real app, you'd use a database.
&lt;/span&gt;&lt;span class="n"&gt;users_db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;next_user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# Simple ID counter
&lt;/span&gt;
&lt;span class="c1"&gt;# --- CORS Middleware ---
# Allows requests from any origin (useful for frontend development)
# For production, you might want to restrict this to specific origins.
&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;allow_origins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;# Allows all origins
&lt;/span&gt;    &lt;span class="n"&gt;allow_credentials&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;allow_methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;# Allows all methods (GET, POST, etc.)
&lt;/span&gt;    &lt;span class="n"&gt;allow_headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;# Allows all headers
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# --- API Endpoints ---
&lt;/span&gt;&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/health&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Check service health&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;health_check&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Simple health check endpoint.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Health check endpoint called&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Create a new user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserCreate&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Creates a new user if email doesn&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t exist and limit is not reached.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;next_user_id&lt;/span&gt; 
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Attempting to create user with email: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Simple validation examples
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users_db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User limit reached. Cannot create more users.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User limit reached&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;users_db&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Email &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; already exists.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;JSONResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Email already exists&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;new_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="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;next_user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;users_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;next_user_id&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# Increment ID for the next user
&lt;/span&gt;    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;new_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; created successfully with ID &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;new_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new_user&lt;/span&gt;


&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Get all users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_users&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Retrieves a list of all created users.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieving all &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users_db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; users.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;users_db&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Local Testing with Gunicorn
&lt;/h3&gt;

&lt;p&gt;Before we move to the docker part, let's make sure our app works with Gunicorn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gunicorn main:app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--workers&lt;/span&gt; 4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--worker-class&lt;/span&gt; uvicorn.workers.UvicornWorker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bind&lt;/span&gt; 0.0.0.0:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quick breakdown:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;main:app&lt;/code&gt; - points to the app variable in main.py&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--workers 4&lt;/code&gt; - I usually go with 2x CPU cores + 1, but adjust as needed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--worker-class uvicorn.workers.UvicornWorker&lt;/code&gt; - this is the magic that lets Gunicorn handle FastAPI's async stuff&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--bind 0.0.0.0:8000&lt;/code&gt; - listen on all interfaces (important for Docker)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hit up &lt;code&gt;http://localhost:8000/docs&lt;/code&gt; in your browser to see the Swagger UI. You can test creating users and retrieving the list.&lt;/p&gt;

&lt;p&gt;Once you're done, hit &lt;code&gt;Ctrl+C&lt;/code&gt; to stop the server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Dockerizing with a Multi-Stage Build
&lt;/h3&gt;

&lt;p&gt;Now for the fun part - let's containerize our app with a multi-stage build to keep things lean:&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;Dockerfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's my Dockerfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# --- Stage 1: Builder ---&lt;/span&gt;
&lt;span class="c"&gt;# Use a specific Python version slim image as the base for building&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;python:3.11-slim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; stage=builder&lt;/span&gt;

&lt;span class="c"&gt;# Set the working directory inside the container&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy only the requirements file first to leverage Docker cache&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt .&lt;/span&gt;

&lt;span class="c"&gt;# Install Python dependencies&lt;/span&gt;
&lt;span class="c"&gt;# Using --no-cache-dir reduces image size slightly&lt;/span&gt;
&lt;span class="c"&gt;# Using --prefix=/install makes it easy to copy installed packages later&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &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;--prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/install &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt


&lt;span class="c"&gt;# --- Stage 2: Runtime ---&lt;/span&gt;
&lt;span class="c"&gt;# Use the same slim Python image for the final runtime environment&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.11-slim&lt;/span&gt;

&lt;span class="c"&gt;# Set the working directory&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy installed packages from the builder stage's /install directory&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /install /usr/local&lt;/span&gt;

&lt;span class="c"&gt;# Copy the application code into the container&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Copy the startup script and make it executable&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; start.sh /app/start.sh&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x /app/start.sh

&lt;span class="c"&gt;# Create a non-root user for security best practices&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;--system&lt;/span&gt; nonroot &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser &lt;span class="nt"&gt;--system&lt;/span&gt; &lt;span class="nt"&gt;--ingroup&lt;/span&gt; nonroot nonroot
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; nonroot&lt;/span&gt;

&lt;span class="c"&gt;# Expose the port the application will run on&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8000&lt;/span&gt;

&lt;span class="c"&gt;# Set environment variables (optional but good practice)&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PYTHONUNBUFFERED=1 &lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PYTHONPATH=/app  &lt;/span&gt;

&lt;span class="c"&gt;# Command to run the application using the startup script&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["/app/start.sh"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why multi-stage? Simple - I want the smallest possible production image. The first stage installs all dependencies, then the second stage only copies what we need, leaving behind all the build tools and cache. Plus, we run as a non-root user for better security.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Create the Startup Script
&lt;/h3&gt;

&lt;p&gt;Let's create a simple script to launch Gunicorn:&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;start.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's what goes in it:&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;# Exit immediately if a command exits with a non-zero status.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="c"&gt;# Print a message to the logs&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Starting application with Gunicorn..."&lt;/span&gt;

&lt;span class="c"&gt;# Execute Gunicorn&lt;/span&gt;
&lt;span class="nb"&gt;exec &lt;/span&gt;gunicorn main:app &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--workers&lt;/span&gt; 4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--worker-class&lt;/span&gt; uvicorn.workers.UvicornWorker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bind&lt;/span&gt; 0.0.0.0:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 7: Build and Run the Docker Container
&lt;/h3&gt;

&lt;p&gt;Finally, let's see this thing in action:&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;# Build the Docker image&lt;/span&gt;
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; fast-microservice &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Run a container from the image&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:8000 &lt;span class="nt"&gt;--name&lt;/span&gt; fast-app fast-microservice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the logs to make sure everything started up correctly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs fast-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now try &lt;code&gt;http://localhost:8000/docs&lt;/code&gt; again - should work just like before, but now it's running in Docker!&lt;/p&gt;

&lt;p&gt;When you're done playing around:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker stop fast-app
docker &lt;span class="nb"&gt;rm &lt;/span&gt;fast-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wrapping Up
&lt;/h3&gt;

&lt;p&gt;In the next part of this series, I'll show you how to use Docker Compose with Traefik as a reverse proxy to handle HTTPS and routing. This setup has served me well for managing multiple services on a single VPS.&lt;/p&gt;

&lt;p&gt;Drop a comment if you run into any issues!&lt;/p&gt;




</description>
      <category>python</category>
      <category>backenddevelopment</category>
      <category>fastapi</category>
      <category>virtualmachine</category>
    </item>
    <item>
      <title>Who Will Bell the Cat? - What I Learned in 2024</title>
      <dc:creator>Aglili Selorm Cecil</dc:creator>
      <pubDate>Mon, 30 Dec 2024 10:11:11 +0000</pubDate>
      <link>https://forem.com/aglili/who-will-bell-the-cat-what-i-learned-in-2024-4kn</link>
      <guid>https://forem.com/aglili/who-will-bell-the-cat-what-i-learned-in-2024-4kn</guid>
      <description>&lt;p&gt;This year was probably one of the best years of my life so far. I loved the most part of it, learnt a lot of things too and i thought it would be wise to share and document the lessons i learnt.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Always Volunteer to Bell the Cat&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From the popular story, the mice in a certain kingdom's lives were threatened by a cat. They held a meeting to decide how to protect themselves. Eventually, they came up with a clever idea: to put a bell around the cat's neck, so they would be alerted whenever the cat was on the move. However, when the time came to volunteer for the mission, no one stepped forward. They were all afraid of losing their lives should the cat wake up.&lt;/p&gt;

&lt;p&gt;This year i learnt the importance of stepping up to do the "hard" or "difficult" work. It’s through these challenges that we grow and truly learn. Everything we know today was once difficult when we first started, and by taking on tasks that seem intimidating, we open the door to new opportunities and personal development.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Consistency is growth&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the beginning of doing these "hard/difficult" things, the urge to give up is very strong because we don’t see immediate results. I often end up doubting my skills and abilities. That’s where consistency comes in. If you did the same thing for one hour every day for a month, by the 30th day, you’d be doing that thing with ease. Most of the things we consume on social media promise us easy success, but as the saying goes, "All good things take time."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Don't to fight things you don't control&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the biggest lessons I learned this year is the importance of letting go of things beyond my control. Life has a way of throwing unexpected challenges our way—situations, people, or outcomes that we cannot influence no matter how hard we try. Fighting these uncontrollable circumstances only leads to frustration, stress, and wasted energy.&lt;/p&gt;

&lt;p&gt;Instead, I’ve learned to focus on what I can control: my attitude, my actions, and how I respond to adversity. Accepting that some things are simply out of my hands has brought me a sense of peace and clarity. It has also helped me channel my energy into productive efforts, rather than getting stuck in a cycle of resistance and negativity.&lt;/p&gt;

&lt;p&gt;As the Stoics often say, “You cannot control the wind, but you can adjust your sails.” This mindset doesn’t mean giving up—it means choosing your battles wisely and finding strength in the areas where you do have power.&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%2F9dgh2d65cflnayt1538k.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dgh2d65cflnayt1538k.jpg" alt="An image that shows what we should fight for" width="800" height="1081"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br&gt;
Each experience, whether good or challenging, has taught me something valuable. I hope you find these useful and perhaps offer some guidance or inspiration as you continue your own journey. Wishing you a happy new year&lt;/p&gt;

</description>
      <category>career</category>
      <category>python</category>
      <category>workplace</category>
    </item>
    <item>
      <title>Demystifying the Python Datetime Library</title>
      <dc:creator>Aglili Selorm Cecil</dc:creator>
      <pubDate>Wed, 22 May 2024 05:45:53 +0000</pubDate>
      <link>https://forem.com/aglili/demystifying-the-python-datetime-library-3hfo</link>
      <guid>https://forem.com/aglili/demystifying-the-python-datetime-library-3hfo</guid>
      <description>&lt;p&gt;The python datetime library is a standard library package that comes with classes for manipulating or working with date and time.&lt;/p&gt;

&lt;p&gt;In this 4 part guide we are going to look at the 4 basic classes this library comes with and how to work with them. These classes are&lt;/p&gt;

&lt;p&gt;1.datetime.datetime&lt;br&gt;
2.datetime.date&lt;br&gt;
3.datetime.timedelta&lt;br&gt;
4.datetime.time&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PART ONE&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;datetime.datetime Class&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;a &lt;em&gt;datetime&lt;/em&gt; is an object which consists of the combination of a date object and a time object.To create a datetime object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#import datetime library
from datetime import datetime

#creating a datetime object
datetime_object = datetime(year,month,day,hour=0,minute=0,second=0,
microsecond=0,tzinfo=None)

# year : MINYEAR &amp;lt;= year &amp;lt;= MAXYEAR 
# month: 1 &amp;lt;= month &amp;lt;= 12
# hour : 0 &amp;lt;= hour &amp;lt; 24,
# minute : 0 &amp;lt;= minute &amp;lt; 60 
# second : 0 &amp;lt;= second &amp;lt; 60
# microsecond: 0 &amp;lt;= microsecond &amp;lt; 1000000

# if we wanted to create a datetime object for 1 January 1999 
date = datetime(1999,1,1)
print(date) 
result =&amp;gt; 1999-01-01 00:00:00 

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

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
&lt;strong&gt;Note&lt;/strong&gt; &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;hour,minute,second and microsecond are optional and default to zero&lt;/li&gt;
&lt;li&gt;Any argument outside the specified ranges raise a ValueError&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This class has some useful methods too&lt;br&gt;
datetime.now() : this returns the datetime object for the current moment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;time_now = datetime.now()
print(time_now)
result =&amp;gt; 2024-05-21 15:49:17.632276
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;datetime.fromisoformat(): Return a datetime corresponding to a date_string in any valid ISO 8601 format, with the following exceptions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;date_string = "2024-05-21 15:49:17.632276"
result = datetime.fromisoformat(date_string)
print("Result Year": result.year)
print("Result Month": result.month)
=&amp;gt;Result Year : 2024
=&amp;gt;Result Month : 5 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;datetime.strptime(): Parses a string representation of a date/time and returns a datetime object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;date_string = "21/05/2024 15:49"
format_string = "%d/%m/%Y %H:%M"
parsed_date = datetime.strptime(date_string, format_string)
print(parsed_date)  

result =&amp;gt; 2024-05-21 15:49:00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;datetime.strftime(): Parses a datetime object into a string given a specific format&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;now = datetime.now()
format_string = "%A, %d %B %Y %I:%M %p"
formatted_date = now.strftime(format_string)
print(formatted_date)
result =&amp;gt; Tuesday, 21 May 2024 03:49 PM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for more information on the datetime formatting codes refer to &lt;a href="https://www.w3schools.com/python/gloss_python_date_format_codes.asp"&gt;w3 schools&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>backend</category>
      <category>beginners</category>
    </item>
    <item>
      <title>My First Month As A Software Engineer</title>
      <dc:creator>Aglili Selorm Cecil</dc:creator>
      <pubDate>Sun, 05 May 2024 11:53:03 +0000</pubDate>
      <link>https://forem.com/aglili/my-first-month-as-a-software-engineer-2eeb</link>
      <guid>https://forem.com/aglili/my-first-month-as-a-software-engineer-2eeb</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;INTRODUCTION&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Like most people in the tech space that I have come across, my journey with tech or computers started as a kid.I had lots of interest in computers and I have carried that interest till this day.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;FIRST IMPRESSIONS&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;As someone who has built or worked with personal projects a lot, every time I see a new codebase the first thing that comes to mind is that "there’s a lot to learn". This is because there's always something newer or something simpler than how I would usually do it. In my first week, I felt overwhelmed by most of the tasks but after that I started to get hold of the standards or inputs that were required of me.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;ON-BOARDING EXPERIENCE&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;My onboarding experience was such a calm journey, my seniors and colleagues really made me feel at home and explained most of the things and standards to me. They also took me through the tools we use and all other stuff I would need to know. As an introvert I barely spoke or asked questions because i was shy but i'm gradually fitting in.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;TECHNICAL CHALLENGES&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Even though I was abreast with OOP, I soon realised it wasn't the standard that I was required to have. I also realised my SQL skills would be put to a test because I only got my hands dirty with "ORMS". So far I have been putting in effort to quickly get the above skills so I can effectively contribute to my team&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;LEARNING CURVE&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;So far the learning curve has been okay, this is because i'm quite knowledgeable with most of the technologies or frameworks we use here. I have also been passed some resources I could use to speed up my learning process&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;COLLABORATION AND TEAM DYNAMICS&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When I started, I was given the basic tasks to perform so as to build some "stamina". In the past weeks I have been given actual tasks that require research and lots of logic to build. I have also been allowed to take some decisions on how things should be and when the team didn't agree, I am made to understand why my decision or choice was not good enough.Interacting with my seniors has given me a specific line of thought to take when I try to tackle or solve problems&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;ACHIEVEMENTS&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;No major achievements but I have been able to close all the tickets i have been assigned without making a mess of anything. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;GROWTH&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I can say I have experienced some level of growth in several aspects. A few of them include my confidence , problem solving skills, time management and communication. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;CONCLUSION&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;So far I have enjoyed my experience at the workplace, the people, the benefits and the learning experience make me happy. Sometimes we may not even remember the simplest things and sometimes we write 100+ lines and everything works on the first run. Everyday isn't the same, we can only try our best and if things don't go well we try another day.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>python</category>
      <category>productivity</category>
      <category>career</category>
    </item>
  </channel>
</rss>
