<?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: Dillion Huston</title>
    <description>The latest articles on DEV Community by Dillion Huston (@dillionhuston).</description>
    <link>https://dev.to/dillionhuston</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%2F2932585%2F9113290f-3924-4da5-bab2-547ea1ce7d8c.png</url>
      <title>DEV Community: Dillion Huston</title>
      <link>https://dev.to/dillionhuston</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dillionhuston"/>
    <language>en</language>
    <item>
      <title>Refactoring a FastAPI Journey and Route API for clarity and maintainability</title>
      <dc:creator>Dillion Huston</dc:creator>
      <pubDate>Sun, 22 Feb 2026 13:16:12 +0000</pubDate>
      <link>https://dev.to/dillionhuston/refactoring-a-fastapi-journey-and-route-api-for-clarity-and-maintainability-2kkk</link>
      <guid>https://dev.to/dillionhuston/refactoring-a-fastapi-journey-and-route-api-for-clarity-and-maintainability-2kkk</guid>
      <description>&lt;p&gt;RouteReality v1.3 is Live&lt;/p&gt;

&lt;p&gt;I’m excited to announce that RouteReality v1.3 is now available. This release focuses on improving stability, cleaning up the core logic, and preparing the system for bigger features in the future. It’s more than just a version bump — it’s a step toward making RouteReality a more reliable and maintainable platform for community-driven, real-time bus tracking.&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%2Fmj642swu81bwivi8ob3o.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%2Fmj642swu81bwivi8ob3o.png" alt="View Journey" width="395" height="860"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What RouteReality Does&lt;/p&gt;

&lt;p&gt;RouteReality is an open-source real-time bus arrival prediction system. It combines static timetable data with live journey events reported by users. The goal is simple: to give people a clearer picture of when their bus is actually arriving, rather than relying solely on the static schedule. The more users interact with the system, the smarter and more accurate the predictions become.&lt;/p&gt;

&lt;p&gt;How RouteReality is Different&lt;/p&gt;

&lt;p&gt;Many Belfast-based bus trackers focus on tracking events after they happen, such as when a bus departs, arrives, or is delayed. These systems are mostly reactive.&lt;/p&gt;

&lt;p&gt;RouteReality, on the other hand, is predictive and community-driven:&lt;/p&gt;

&lt;p&gt;It predicts bus arrival times instead of just reporting past events.&lt;/p&gt;

&lt;p&gt;It blends static timetables with live user reports for more accurate predictions.&lt;/p&gt;

&lt;p&gt;It uses community input to improve accuracy over time, so the system learns from repeated journeys.&lt;/p&gt;

&lt;p&gt;Predictions include a confidence measure, showing how reliable the estimate is.&lt;/p&gt;

&lt;p&gt;It’s open-source and developer-friendly, making it easy for others to contribute or extend the system.&lt;/p&gt;

&lt;p&gt;What’s New in v1.3&lt;/p&gt;

&lt;p&gt;This update focuses on stability, reliability, and improving the foundations of the system.&lt;/p&gt;

&lt;p&gt;Stabilization and Improvements&lt;/p&gt;

&lt;p&gt;Added UI screenshots to the README to help new developers understand the app.&lt;/p&gt;

&lt;p&gt;Improved handling of journey event types for a clearer journey lifecycle.&lt;/p&gt;

&lt;p&gt;Expanded prediction payloads to include context such as recent event counts, source metadata, and historical data.&lt;/p&gt;

&lt;p&gt;Introduced more robust logging and instrumentation throughout the prediction and event handling layers.&lt;/p&gt;

&lt;p&gt;Naming and Refactor&lt;/p&gt;

&lt;p&gt;Renamed key prediction fields (for example, static_dt is now reference_time) for better clarity and consistency.&lt;/p&gt;

&lt;p&gt;Centralized prediction refresh logic to reduce duplicated code and improve maintainability.&lt;/p&gt;

&lt;p&gt;Improved timetable loading and fallback logic for situations where static data is limited.&lt;/p&gt;

&lt;p&gt;Bug Fixes&lt;/p&gt;

&lt;p&gt;Fixed crashes caused by unsafe timetable unpacking.&lt;/p&gt;

&lt;p&gt;Stabilized prediction confidence scoring when limited data is available.&lt;/p&gt;

&lt;p&gt;Improved API error handling for invalid routes or stops.&lt;/p&gt;

&lt;p&gt;This release sets the stage for v2, which will include features like authentication, personalized experiences, more sophisticated prediction models, and deeper community engagement tools.&lt;/p&gt;

&lt;p&gt;You can view the full v1.3 release notes here:&lt;br&gt;
&lt;a href="https://github.com/dillionhuston/RouteReality/releases/tag/V1.3" rel="noopener noreferrer"&gt;https://github.com/dillionhuston/RouteReality/releases/tag/V1.3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The updated README also includes guides and screenshots to help you get started:&lt;br&gt;
&lt;a href="https://github.com/dillionhuston/RouteReality/blob/main/README.md" rel="noopener noreferrer"&gt;https://github.com/dillionhuston/RouteReality/blob/main/README.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What’s Next&lt;/p&gt;

&lt;p&gt;We’re already working toward:&lt;/p&gt;

&lt;p&gt;User accounts and preferences&lt;/p&gt;

&lt;p&gt;Prediction models that consider time-of-day patterns and historical trends&lt;/p&gt;

&lt;p&gt;Improved mobile-friendly UI and performance&lt;/p&gt;

&lt;p&gt;Stronger community reporting and feedback loops&lt;/p&gt;

&lt;p&gt;A big thank you to everyone who has tested, reported bugs, and provided feedback. Your contributions are helping shape the future of RouteReality.&lt;/p&gt;

&lt;p&gt;Happy building and coding!&lt;/p&gt;

</description>
      <category>python</category>
      <category>opensource</category>
      <category>fastapi</category>
      <category>news</category>
    </item>
    <item>
      <title>Fixing the Ghost Bus Problem: How Weighted Averages Can Improve Real-Time Public Transit Predictions</title>
      <dc:creator>Dillion Huston</dc:creator>
      <pubDate>Wed, 11 Feb 2026 19:25:57 +0000</pubDate>
      <link>https://dev.to/dillionhuston/fixing-the-ghost-bus-problem-how-weighted-averages-can-improve-real-time-public-transit-predictions-594g</link>
      <guid>https://dev.to/dillionhuston/fixing-the-ghost-bus-problem-how-weighted-averages-can-improve-real-time-public-transit-predictions-594g</guid>
      <description>&lt;p&gt;Many users (myself included) have noticed a recurring issue with the Belfast bus system—timing discrepancies and "ghost buses" that don’t show up. Buses often arrive either too early, too late, or not at all. This issue has been ongoing since late December 2023, with over 10,000 metro services cancelled or missing in 12 months, causing frustration among commuters.&lt;/p&gt;

&lt;p&gt;The Minister for Transport has even commented that "ghost buses" are "simply not acceptable."&lt;/p&gt;

&lt;p&gt;The Data Problem&lt;/p&gt;

&lt;p&gt;The crux of the issue is simple: static timetables don't align with reality. According to reports, 2,500 complaints have been made to Translink, with passengers frustrated by buses that “disappear” from digital displays, or app schedules that don't reflect cancellations at all.&lt;/p&gt;

&lt;p&gt;These discrepancies lead to wasted time, missed connections, and decreased trust in public transport. The solution? A real-time arrival prediction model that uses historical data and user-reported events, rather than relying solely on static schedules.&lt;/p&gt;

&lt;p&gt;Enter Weighted Averages&lt;/p&gt;

&lt;p&gt;In statistics, weighted averages allow us to make certain data points more important than others. This is particularly useful in cases like the Belfast bus system, where the most recent data is likely the most accurate predictor of future events.&lt;/p&gt;

&lt;p&gt;A weighted average works by assigning a weight (or "confidence score") to each data point, and adjusting predictions based on those weights. In this case, the more recent bus arrival times are given higher weights since they reflect the latest, most relevant information.&lt;/p&gt;

&lt;p&gt;How It Works in Practice&lt;/p&gt;

&lt;p&gt;For instance, imagine we have the following bus arrival times:&lt;/p&gt;

&lt;p&gt;08:02&lt;/p&gt;

&lt;p&gt;08:05&lt;/p&gt;

&lt;p&gt;08:07&lt;/p&gt;

&lt;p&gt;08:10&lt;/p&gt;

&lt;p&gt;08:12&lt;/p&gt;

&lt;p&gt;We assign weights like this (newer data gets higher weight):&lt;/p&gt;

&lt;p&gt;08:12 = 5&lt;/p&gt;

&lt;p&gt;08:10 = 4&lt;/p&gt;

&lt;p&gt;08:07 = 3&lt;/p&gt;

&lt;p&gt;08:05 = 2&lt;/p&gt;

&lt;p&gt;08:02 = 1&lt;/p&gt;

&lt;p&gt;Now, we convert these times into minutes since midnight:&lt;/p&gt;

&lt;p&gt;08:12 = 492 minutes&lt;/p&gt;

&lt;p&gt;08:10 = 490 minutes&lt;/p&gt;

&lt;p&gt;08:07 = 487 minutes&lt;/p&gt;

&lt;p&gt;08:05 = 485 minutes&lt;/p&gt;

&lt;p&gt;08:02 = 482 minutes&lt;/p&gt;

&lt;p&gt;Next, we multiply each time by its corresponding weight:&lt;/p&gt;

&lt;p&gt;08:12 (492m) × 5 = 2460&lt;/p&gt;

&lt;p&gt;08:10 (490m) × 4 = 1960&lt;/p&gt;

&lt;p&gt;08:07 (487m) × 3 = 1461&lt;/p&gt;

&lt;p&gt;08:05 (485m) × 2 = 970&lt;/p&gt;

&lt;p&gt;08:02 (482m) × 1 = 482&lt;/p&gt;

&lt;p&gt;Sum them up:&lt;/p&gt;

&lt;p&gt;2460 + 1960 + 1461 + 970 + 482 = 7333&lt;/p&gt;

&lt;p&gt;Then, we sum the weights:&lt;/p&gt;

&lt;p&gt;5 + 4 + 3 + 2 + 1 = 15&lt;/p&gt;

&lt;p&gt;Finally, we calculate the weighted average by dividing the total sum by the total weight:&lt;/p&gt;

&lt;p&gt;7333 ÷ 15 = 488.87 minutes past midnight, which is 08:08:52 (rounded to 08:09).&lt;/p&gt;

&lt;p&gt;This weighted average gives us a more accurate prediction of the bus arrival time, based on real-time performance rather than relying on outdated, static schedules.&lt;/p&gt;

&lt;p&gt;How This Solves the Ghost Bus Problem&lt;/p&gt;

&lt;p&gt;Here’s where the magic happens: by using weighted averages to calculate real-time predictions, we move away from static timetables and instead create dynamic predictions that react to the real-time performance of buses.&lt;/p&gt;

&lt;p&gt;Every time a bus arrives, that data point gets added to the system, and the system recalculates the expected time for the next bus. The more recent arrivals have a higher weight, meaning the predicted arrival time always reflects the latest performance.&lt;/p&gt;

&lt;p&gt;For passengers, this means no more waiting around in the rain, unsure when (or if) their bus will arrive. Instead, they get a live ETA based on actual performance, not just scheduled times.&lt;/p&gt;

&lt;p&gt;Why This Matters for Developers&lt;/p&gt;

&lt;p&gt;The concept of weighted averages is straightforward, but its real-world application in transport systems shows the power of data-driven predictions. In a public transit scenario like this, relying on historical performance (rather than static timetables) makes a huge difference in delivering a better user experience.&lt;/p&gt;

&lt;p&gt;The model could be further enhanced with machine learning to predict delays, cancellations, and bus frequency, factoring in variables like traffic patterns, weather conditions, or driver availability.&lt;/p&gt;

&lt;p&gt;For developers working on similar projects, this kind of dynamic prediction model has wide-ranging applications—any system that relies on real-time data (e.g., ride-sharing, delivery systems, public transit apps) can benefit from this approach.&lt;/p&gt;

&lt;p&gt;TL;DR&lt;/p&gt;

&lt;p&gt;To fix the ghost bus problem in Belfast, we use weighted averages to predict bus arrival times dynamically. By giving more weight to recent bus data, we move away from static timetables and create more accurate, real-time predictions, ultimately improving the passenger experience.&lt;/p&gt;

&lt;p&gt;Closing Thoughts&lt;/p&gt;

&lt;p&gt;This solution illustrates a simple but effective way of using historical performance data to improve real-time predictions. It also opens up opportunities to build better, smarter systems that adapt to the real world, helping developers address similar challenges across various industries.&lt;/p&gt;

&lt;p&gt;Check the project out &lt;a href="https://github.com/dillionhuston/RouteReality" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>python</category>
      <category>algorithms</category>
      <category>database</category>
    </item>
    <item>
      <title>Why Use Weighted Averages for Journey Arrival Predictions?</title>
      <dc:creator>Dillion Huston</dc:creator>
      <pubDate>Sun, 08 Feb 2026 15:40:41 +0000</pubDate>
      <link>https://dev.to/dillionhuston/why-use-weighted-averages-for-journey-arrival-predictions-c12</link>
      <guid>https://dev.to/dillionhuston/why-use-weighted-averages-for-journey-arrival-predictions-c12</guid>
      <description>&lt;p&gt;Release: V1.1 – 08-02-2026&lt;/p&gt;

&lt;p&gt;Accurately predicting arrival times is harder than it looks. Static timetables rarely reflect reality, and user-reported data can be noisyand inconsistent. In V1.1, the prediction system takes a big step forward by introducing weighted averaging of recent user journey data, alongside a confidence scoring and improved fallback logic.&lt;/p&gt;

&lt;p&gt;This release focuses on one core idea:&lt;/p&gt;

&lt;p&gt;Recent, real-world behaviour matters more than theoretical schedules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem&lt;/strong&gt;&lt;br&gt;
Traditional arrival prediction systems rely heavily on static timetables:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;They assume journeys behave the same every day&lt;/li&gt;
&lt;li&gt;They don’t adapt to traffic, delays, or personal habits&lt;/li&gt;
&lt;li&gt;They fail badly when conditions change&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On the other hand, user-reported journey data is closer to reality. But it comes with its own issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some data points are old&lt;/li&gt;
&lt;li&gt;Some are outliers (missed stops, breaks, anomalies)&lt;/li&gt;
&lt;li&gt;Sometimes there’s not enough data at all#&lt;/li&gt;
&lt;li&gt;So the real challenge is:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How do you trust real-world data without letting bad or outdated data ruin predictions?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution: Weighted Averages&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of treating all journey data equally, V1.1 introduces weighted averaging, where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recent journeys have more influence&lt;/li&gt;
&lt;li&gt;Older journeys gradually matter less&lt;/li&gt;
&lt;li&gt;Outliers are naturally diluted&lt;/li&gt;
&lt;li&gt;Predictions adapt over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allows the system to learn without overreacting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Weighted Averaging Works (Concept)&lt;/strong&gt;&lt;br&gt;
Each past journey contributes to the prediction. But not equally.&lt;/p&gt;

&lt;p&gt;Example weighting strategy:&lt;/p&gt;

&lt;p&gt;Last journey: weight 0.5&lt;/p&gt;

&lt;p&gt;Journey before that: weight 0.3&lt;/p&gt;

&lt;p&gt;Older journey: weight 0.2&lt;/p&gt;

&lt;p&gt;The predicted arrival time becomes:&lt;/p&gt;

&lt;p&gt;(predicted_time) =&lt;br&gt;
(journey_1 × 0.5) +&lt;br&gt;
(journey_2 × 0.3) +&lt;br&gt;
(journey_3 × 0.2)&lt;/p&gt;

&lt;p&gt;If a user’s commute suddenly changes (roadworks, new route, traffic pattern), and a report is submitted. The new journey-event data quickly pulls the prediction in the right direction, without instantly removing historical context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-World Explanation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Think about estimating how long it takes you to get to work.&lt;/p&gt;

&lt;p&gt;You wouldn’t say:&lt;/p&gt;

&lt;p&gt;“Google Maps says 30 minutes, so it’s always 30 minutes.”&lt;/p&gt;

&lt;p&gt;You’d think:&lt;/p&gt;

&lt;p&gt;Yesterday it took 38 minutes (traffic)&lt;br&gt;
The day before it took 35&lt;/p&gt;

&lt;p&gt;Last month it was closer to 28&lt;/p&gt;

&lt;p&gt;Naturally, you’d trust yesterday more than last month.&lt;/p&gt;

&lt;p&gt;That’s weighted averaging. We humans do it instinctively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example in Practice&lt;/strong&gt;&lt;br&gt;
Let’s say a user reports these recent arrival times:&lt;/p&gt;

&lt;p&gt;Journey Arrival Time&lt;br&gt;
Most recent 37 mins&lt;br&gt;
Previous    35 mins&lt;br&gt;
Older   29 mins&lt;/p&gt;

&lt;p&gt;With weights applied:&lt;br&gt;
(37 × 0.5) + (35 × 0.3) + (29 × 0.2)&lt;br&gt;
= 18.5 + 10.5 + 5.8&lt;br&gt;
= 34.8 minutes&lt;/p&gt;

&lt;p&gt;Instead of blindly predicting 29 (timetable) or 37 (last journey), the system predicts ~35 minutes, which is far more realistic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s New in V1.1?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Added:&lt;br&gt;
Weighted averaging of recent journey data&lt;br&gt;
Confidence scoring for arrival predictions&lt;/p&gt;

&lt;p&gt;Clear UI distinction between:&lt;br&gt;
Predicted times&lt;br&gt;
User-reported events and times&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Changed&lt;/strong&gt;&lt;br&gt;
Prediction logic now prioritises recent user data over static timetables&lt;br&gt;
Improved fallback behaviour when data is sparse or unavailable&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fixed&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Edge cases where no recent journey data exists&lt;br&gt;
Improved journey creation process&lt;br&gt;
Better error handling for invalid or malformed data&lt;/p&gt;

&lt;p&gt;Why does this matter?&lt;/p&gt;

&lt;p&gt;This approach makes the system:&lt;br&gt;
More adaptive&lt;br&gt;
More honest about uncertainty&lt;br&gt;
More reflective of real-world behaviour&lt;/p&gt;

&lt;p&gt;It builds user trust over time and creates a more accurate model&lt;/p&gt;

&lt;p&gt;Instead of pretending predictions are always correct. V1.1 embraces probability, confidence, and learning — which is exactly how good systems should behave.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>coding</category>
      <category>backend</category>
      <category>python</category>
    </item>
    <item>
      <title>Deploying RouteReality: The Real Challenges of Running a Live, Real-Time Bus Prediction System</title>
      <dc:creator>Dillion Huston</dc:creator>
      <pubDate>Tue, 03 Feb 2026 18:12:33 +0000</pubDate>
      <link>https://dev.to/dillionhuston/deploying-routereality-the-real-challenges-of-running-a-live-real-time-bus-prediction-system-50ef</link>
      <guid>https://dev.to/dillionhuston/deploying-routereality-the-real-challenges-of-running-a-live-real-time-bus-prediction-system-50ef</guid>
      <description>&lt;p&gt;RouteReality: Building a Community-Powered Bus Tracker for Belfast&lt;br&gt;
When I first launched &lt;a href="https://routereality.co.uk" rel="noopener noreferrer"&gt;routereality.co.uk&lt;/a&gt;, the goal was simple: give Belfast and Northern Ireland bus users better, more accurate arrival predictions than the official sources provide. Unlike apps that rely solely on scheduled timetables or delayed GPS feeds, RouteReality is fully community-powered.&lt;/p&gt;

&lt;p&gt;Users check predicted times, wait at the stop, and tap to report when the bus actually arrives. Every report feeds back into the system, refining predictions for everyone in real time.&lt;/p&gt;

&lt;p&gt;Today, the site runs 24/7, covering 100+ routes and 17,000+ stops, with live updates constantly streaming in from real users across the country. But building and deploying a system like this one that people depend on every day was far from straightforward. Here are the main problems I encountered along the way, and how they shaped the project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Keeping Real-Time Data Accurate When Users Are Always Reporting&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The core of RouteReality is user-submitted arrival reports. In theory, more reports = better predictions. In practice, the live nature of the system creates immediate challenges.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Timing mismatches and outliers&lt;/strong&gt; — People report arrivals at slightly different times due to boarding the bus, network delays, or simply tapping a second too early/late. Early on, a few bad reports could mess with predictions by minutes. I had to implement outlier detection (ignoring reports more than ~3 minutes off the median) and time window clustering to group reports for the same bus instance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Duplicate or spam reports&lt;/strong&gt; — With users constantly using the site, especially during  peak commute hours, the same bus stop could receive multiple reports in seconds. Without careful deduplication logic (based on user session, location hints, and timestamp proximity), predictions would jump erratically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sparse data in the early days&lt;/strong&gt;— When the user base was small, many stops had zero or one report per day. Predictions defaulted to timetable estimates, but users expected better. Bootstrapping accuracy required careful fallback logic and incentives to encourage early reporting.&lt;/p&gt;

&lt;p&gt;**2. Scalability and Performance Under Constant User Load&lt;br&gt;
**Unlike a static site, RouteReality has users actively querying predictions and submitting reports at all hours. The system needs to handle concurrent reads/writes without lag, especially during busy periods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database pressure&lt;/strong&gt; — Storing millions of timestamped reports requires a time-series-friendly setup. Early prototypes using a standard relational DB choked on write-heavy loads. Moving to a more scalable store (with proper indexing and partitioning by route/stop/day) prevented slowdowns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server costs and monitoring&lt;/strong&gt; — Running 24/7 means no off-hours for heavy maintenance. Unexpected spikes in traffic (e.g., bad weather driving more bus usage) could spike costs or cause brief slowdowns. Setting up real-time monitoring dashboards became essential to catch issues before users noticed.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Live Deployment Nightmares:&lt;/strong&gt; No Room for Downtime
Deploying updates to a live system with constant user activity is unforgiving. Even a 30-second outage frustrates someone waiting at a rainy stop.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Zero-downtime deploys&lt;/strong&gt; — Early deploys caused brief interruptions as the server restarted. Implementing blue-green deployments or rolling updates eliminated that pain, but required more infrastructure setup.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Bug fixes under pressure *&lt;/em&gt;— A subtle bug in report aggregation once caused predictions to drift by 5+ minutes for a popular route during evening rush. Users noticed immediately and reported it (ironically helping debug). Hotfixes had to be rolled out without breaking ongoing sessions.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Testing in production-like conditions *&lt;/em&gt;— Local tests missed real-world issues like network latency on mobile data, varied device clocks, or users in poor signal areas. Gradual rollouts and feature flags became my best friends.&lt;/p&gt;

&lt;p&gt;Lessons Learned and What's Next&lt;br&gt;
Launching RouteReality taught me that real-time, user-dependent systems are as much about people as technology. Community engagement is the biggest variable. The more people report, the better it gets, but getting that branch started requires patience and careful tuning.&lt;/p&gt;

&lt;p&gt;Despite the challenges, the system is live, improving daily, and already helping commuters in Belfast and beyond. Future plans include better outlier handling, optional location-based reporting (with privacy controls), and deeper analytics to spot patterns (e.g., chronically late routes).&lt;/p&gt;

&lt;p&gt;If you're a regular user, thank you for every report. It directly makes predictions more accurate for everyone. And if you haven't tried it yet, head to the journey page and start reporting. The more we all contribute, the better RouteReality becomes.&lt;/p&gt;

&lt;p&gt;Always cross-check with official Translink sources, as RouteReality remains an independent community project.&lt;/p&gt;

&lt;p&gt;Posted February 2026&lt;/p&gt;

</description>
      <category>hackathon</category>
      <category>programming</category>
      <category>analytics</category>
      <category>python</category>
    </item>
    <item>
      <title>Deploying My First Task Automation App — Lessons Learned and Tips for Beginners</title>
      <dc:creator>Dillion Huston</dc:creator>
      <pubDate>Tue, 25 Nov 2025 21:36:24 +0000</pubDate>
      <link>https://dev.to/dillionhuston/deploying-my-first-task-automation-app-lessons-learned-and-tips-for-beginners-4dpl</link>
      <guid>https://dev.to/dillionhuston/deploying-my-first-task-automation-app-lessons-learned-and-tips-for-beginners-4dpl</guid>
      <description>&lt;p&gt;Hey everyone! &lt;br&gt;
I just shipped my first real project to production: &lt;strong&gt;&lt;a href="https://dillonhtask.netlify.app/" rel="noopener noreferrer"&gt;https://dillonhtask.netlify.app/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It’s a small but practical &lt;strong&gt;task automation app&lt;/strong&gt;. Right now the live version focuses on &lt;strong&gt;sending email reminders&lt;/strong&gt;, while the local version (on GitHub) includes an extra feature that automatically cleans up old files. More features are in the pipeline — this is just v0.1!&lt;/p&gt;

&lt;p&gt;The main goal wasn’t to build the next Todoist killer. It was to finally go through the entire process of taking something from “works on my machine” → actually live on the internet, and document all the face-palm moments along the way.&lt;/p&gt;

&lt;p&gt;Spoiler: there were many.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the App Does Right Now
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Online: Send yourself (or others) email reminders at a scheduled time
&lt;/li&gt;
&lt;li&gt;Local-only (for now): Auto-delete old downloads/temp files
&lt;/li&gt;
&lt;li&gt;Planned: More automations, proper backend, cron jobs, webhooks, notifications, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even in its current tiny form, I already use the reminder feature daily.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Painful (But Invaluable) Problems I Hit
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. “It Works on My Machine” Syndrome
&lt;/h3&gt;

&lt;p&gt;Everything was perfect locally. Deployed to Netlify → half the CSS and all images 404’d.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Root cause:&lt;/strong&gt; I was using relative paths like &lt;code&gt;../assets/logo.png&lt;/code&gt;. They work when you open &lt;code&gt;index.html&lt;/code&gt; directly, but break when served from a sub-route.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Switch to root-relative paths → &lt;code&gt;/assets/logo.png&lt;/code&gt; (note the leading slash).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Production doesn’t care about your local file system. Always test the production build locally (&lt;code&gt;npm run build &amp;amp;&amp;amp; serve -s build&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Dreaded SPA Refresh 404
&lt;/h3&gt;

&lt;p&gt;Clicking a React Router link? Fine.&lt;br&gt;&lt;br&gt;
Direct visit or page refresh on &lt;code&gt;/settings&lt;/code&gt;? 404 city.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Netlify (like most static hosts) tries to find a real file at that path. There isn’t one — it’s client-side routing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Add a &lt;code&gt;_redirects&lt;/code&gt; file inside the &lt;code&gt;public/&lt;/code&gt; folder (or at the build output root):&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
text
/*    /index.html   200
That single line tells Netlify: “For every route, serve index.html but keep the 200 status” → React Router takes over.
3. Pointing Netlify at the Wrong Folder
My project looked like this at one point:
textproject/
├── src/
├── public/
├── build/
├── random-old-crap/
└── who-knows-what/
Netlify kept deploying an empty site because the publish directory was wrong or the build folder name changed between frameworks.
Fix: Cleaned everything up and explicitly set:

Build command: npm run build
Publish directory: dist (Vite) or build (Create React App)

4. Thinking Ahead: Environment Variables
The app doesn’t have a backend yet, but I already added .env variables on Netlify for future email API keys, etc.
Why bother now? Because adding them later means redeploying and potentially exposing secrets if you forget.
My Exact Deployment Checklist (Works Every Time Now)

npm run build locally → verify it works with serve -s build
Push to GitHub
Netlify → “New site from Git”
Connect repo
Settings:
Build command: npm run build
Publish directory: dist (or build)

Add _redirects file if it’s an SPA
Deploy → profit

Total time once everything is clean: ~60 seconds.
Biggest Takeaways (Especially for Beginners)

Deployment is a skill on its own — treat it as such
Local ≠ Production. Always test the actual build output
Use root-relative paths for assets (/assets/...)
For SPAs on Netlify/Vercel: you need a rewrite/redirect rule
Clean project structure saves hours of debugging
Set up environment variables early
Automate nothing until you’ve deployed something

What’s Next?

Bring the file-cleanup feature online (needs a tiny backend)
FastAPI + JWT backend
Scheduled tasks (Cron-like)
GitHub Actions integration
More automations (RSS → email, price tracking, etc.)

This was a “small” project, but it taught me more about real-world development than any tutorial ever did.
If you’ve deployed something recently and hit weird bugs (especially the infamous refresh 404), drop your war stories in the comments — I’d love to hear how you solved them! 🚀
P.S. Here’s the live app again: https://dillonhtask.netlify.app/
#webdev #beginners #deployment #react #netlify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>automation</category>
      <category>devops</category>
      <category>beginners</category>
      <category>showdev</category>
    </item>
    <item>
      <title>SHA-256 File Hasher &amp; Duplicate Finder in Python</title>
      <dc:creator>Dillion Huston</dc:creator>
      <pubDate>Sat, 25 Oct 2025 17:07:11 +0000</pubDate>
      <link>https://dev.to/dillionhuston/sha-256-file-hasher-duplicate-finder-in-python-217h</link>
      <guid>https://dev.to/dillionhuston/sha-256-file-hasher-duplicate-finder-in-python-217h</guid>
      <description>&lt;p&gt;I’ve just finished a &lt;strong&gt;modular Python project&lt;/strong&gt; I’m really excited about — a &lt;strong&gt;SHA-256 File Hasher &amp;amp; Duplicate Finder&lt;/strong&gt;. This tool is designed to help developers, sysadmins, or anyone dealing with lots of files to quickly detect duplicates and manage storage efficiently.  &lt;/p&gt;

&lt;p&gt;It’s fully &lt;strong&gt;object-oriented&lt;/strong&gt; and comes with a &lt;strong&gt;clean API&lt;/strong&gt;, making it easy to integrate into other Python projects or use as a standalone tool. Whether you’re scanning a single file or an entire folder recursively, it computes &lt;strong&gt;SHA-256 hashes&lt;/strong&gt; efficiently and keeps track of duplicates for you.  &lt;/p&gt;

&lt;p&gt;I built this to be &lt;strong&gt;lightweight, reliable, and zero-dependency&lt;/strong&gt;, so you don’t need to install any extra packages. It’s a great example of combining practical Python scripting with &lt;strong&gt;clean software design&lt;/strong&gt; — something that’s useful, shareable, and a nice addition to your GitHub portfolio.  &lt;/p&gt;

&lt;p&gt;If you’re learning Python, building projects, or just want to tinker with file management tools, this project is perfect to explore, experiment with, and contribute to.  &lt;/p&gt;

&lt;p&gt;I’m also growing a &lt;strong&gt;Python &amp;amp; dev community&lt;/strong&gt; on Discord where beginners and experienced programmers can hang out, share projects, get help, and collaborate. I’d love for you to join — whether you want to test the tool, discuss Python, or just meet like-minded devs.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Join here:&lt;/strong&gt; &lt;a href="https://discord.gg/cBuEjejr" rel="noopener noreferrer"&gt;https://discord.gg/cBuEjejr&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;If you have ideas for improvements, want to contribute, or just want to chat about Python projects, this is the place! Let’s make it a friendly, active community for learning, sharing, and building cool things together.  &lt;/p&gt;

&lt;p&gt;Check out the GitHub repo here: &lt;a href="https://github.com/dillionhuston/SHA-256-File-Hasher" rel="noopener noreferrer"&gt;https://github.com/dillionhuston/SHA-256-File-Hasher&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Can’t wait to see what you all think — and I hope to see you in the Discord server! 🚀&lt;/p&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>From Kiddie Projects to Production-Ready APIs: My FastAPI Journey at 18</title>
      <dc:creator>Dillion Huston</dc:creator>
      <pubDate>Wed, 13 Aug 2025 11:43:36 +0000</pubDate>
      <link>https://dev.to/dillionhuston/from-kiddie-projects-to-production-ready-apis-my-fastapi-journey-at-18-1699</link>
      <guid>https://dev.to/dillionhuston/from-kiddie-projects-to-production-ready-apis-my-fastapi-journey-at-18-1699</guid>
      <description>&lt;h1&gt;
  
  
  From Kiddie Projects to Production Ready APIs: My FastAPI Journey at 18
&lt;/h1&gt;

&lt;p&gt;I’m 18 and from West Belfast. I started like most self-taught devs — small Python scripts, half-finished tools, and code that kind of worked if I didn’t touch it too much.&lt;/p&gt;

&lt;p&gt;Lately I’ve been getting more serious. I built a proper backend system using FastAPI, with file uploads, JWT authentication, background tasks, and a full deployment setup.&lt;/p&gt;

&lt;p&gt;Not here to pitch anything. Just sharing what I built, what went wrong, and what I learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I moved from Flask to FastAPI
&lt;/h2&gt;

&lt;p&gt;I used Flask for a while. It’s great for small projects, but once I started adding real features like auth, file handling, and background jobs, things got messy.&lt;/p&gt;

&lt;p&gt;FastAPI felt more structured without being overcomplicated. A few things stood out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request validation with Pydantic was way cleaner
&lt;/li&gt;
&lt;li&gt;Async support was baked in from the start
&lt;/li&gt;
&lt;li&gt;It auto-generates API docs, which was actually useful for testing
&lt;/li&gt;
&lt;li&gt;Strong type hints made my editor smarter and saved me from dumb mistakes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;Here’s what’s working right now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auth system using JWT
&lt;/li&gt;
&lt;li&gt;File uploads with SHA-256 hash checks
&lt;/li&gt;
&lt;li&gt;File listing and secure downloads
&lt;/li&gt;
&lt;li&gt;Background task scheduling with Celery and Redis
&lt;/li&gt;
&lt;li&gt;Docker-based deployment to a Hetzner server using Coolify
&lt;/li&gt;
&lt;li&gt;Basic test coverage using pytest&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole thing runs through FastAPI with async endpoints. It’s not perfect but it works well, and it’s clean enough to share.&lt;/p&gt;

&lt;h2&gt;
  
  
  What went wrong
&lt;/h2&gt;

&lt;p&gt;Nothing crazy, but I definitely hit some walls.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dependency injection in FastAPI took a while to wrap my head around
&lt;/li&gt;
&lt;li&gt;Testing async routes was different than what I was used to with Flask
&lt;/li&gt;
&lt;li&gt;Uploading large files without blocking the whole server needed some extra work
&lt;/li&gt;
&lt;li&gt;Docker config took more trial and error than expected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of it came down to learning by doing. I broke it, then fixed it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I’d tell other devs
&lt;/h2&gt;

&lt;p&gt;Don’t overthink things early on. Build something useful, then polish it later.&lt;/p&gt;

&lt;p&gt;Start using type hints early. They don’t seem important until your project gets bigger, then they save you from major headaches.&lt;/p&gt;

&lt;p&gt;If something feels overcomplicated, break it down and rebuild it. That’s how I learned most of this stuff.&lt;/p&gt;

&lt;p&gt;And don’t wait until you're an “expert” to put your code out there. You learn more when other people can see what you’re working on.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next
&lt;/h2&gt;

&lt;p&gt;I’m planning to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an API key system for public usage
&lt;/li&gt;
&lt;li&gt;Improve the admin tools
&lt;/li&gt;
&lt;li&gt;Write a proper setup guide for others to use the project&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;This is the first time I felt like I built something solid end to end. I’m not in uni, I’m not working at a tech company, and I’m not using AI to do the work for me.&lt;/p&gt;

&lt;p&gt;Just writing code and building something that solves a real problem.&lt;/p&gt;

&lt;p&gt;If you’re working on something similar or want feedback on your own backend, feel free to drop a comment.&lt;/p&gt;

&lt;p&gt;Here’s the repo if you want to check it out:  &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/dillionhuston/Task-Automation-API" rel="noopener noreferrer"&gt;https://github.com/dillionhuston/Task-Automation-API&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;fastapi python backend selftaught devjourney programming&lt;/code&gt;&lt;/p&gt;

</description>
      <category>fastapi</category>
      <category>python</category>
      <category>backend</category>
      <category>selftaught</category>
    </item>
    <item>
      <title>Adding SMTP Email Notifications to FastAPI Using smtplib and Environment Variables</title>
      <dc:creator>Dillion Huston</dc:creator>
      <pubDate>Sun, 03 Aug 2025 15:05:04 +0000</pubDate>
      <link>https://dev.to/dillionhuston/adding-smtp-email-notifications-to-fastapi-using-smtplib-and-environment-variables-4mp8</link>
      <guid>https://dev.to/dillionhuston/adding-smtp-email-notifications-to-fastapi-using-smtplib-and-environment-variables-4mp8</guid>
      <description>&lt;p&gt;In my &lt;strong&gt;Task Automation API&lt;/strong&gt;, I added email notification support using Python’s &lt;code&gt;smtplib&lt;/code&gt;. The setup is minimal, uses no extra packages, and leverages environment variables to securely manage SMTP credentials.&lt;/p&gt;

&lt;p&gt;Here’s a breakdown of the implementation, inspired by this commit:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/dillionhuston/Task-Automation-API/commit/a4f37e1cbed5fc17b920ea27ae0be6b6a598234d#diff-22ca66176c6879ee3daf6f501b7311570793d61040a177b2ed0ea289d558744eR1-R72" rel="noopener noreferrer"&gt;View commit on GitHub&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Email Sending Function with smtplib
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;smtplib&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;email.mime.text&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MIMEText&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;email.mime.multipart&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MIMEMultipart&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SMTP_SENDER&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SMTP_PASSWORD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;smtp_server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SMTP_SERVER&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;smtp_port&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SMTP_PORT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;587&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MIMEMultipart&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;From&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;To&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recipient&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Subject&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MIMEText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plain&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;smtplib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SMTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;smtp_server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;smtp_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;starttls&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;p&gt;To keep secrets out of the codebase, define these in your &lt;code&gt;.env&lt;/code&gt; file or server environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SMTP_SENDER&lt;/code&gt;: Your email address&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SMTP_PASSWORD&lt;/code&gt;: SMTP password or app-specific password&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SMTP_SERVER&lt;/code&gt;: SMTP host, e.g., &lt;code&gt;smtp.gmail.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SMTP_PORT&lt;/code&gt;: Port number, usually &lt;code&gt;587&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How I Use It
&lt;/h2&gt;

&lt;p&gt;After a user schedules a task, once and it’s validated, I call &lt;code&gt;send_email&lt;/code&gt; to notify them:&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="nf"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;File Upload Successful&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&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;Your file &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; was uploaded and verified.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why This Approach?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No external dependencies&lt;/li&gt;
&lt;li&gt;Secure configuration with environment variables&lt;/li&gt;
&lt;li&gt;Easy to extend for HTML emails or attachments later&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;Adding SMTP email with &lt;code&gt;smtplib&lt;/code&gt; is a lightweight, effective way to send notifications in your FastAPI app. This pattern fits nicely in automation workflows like mine.&lt;/p&gt;

&lt;p&gt;Check out the full commit for details:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/dillionhuston/Task-Automation-API/commit/a4f37e1cbed5fc17b920ea27ae0be6b6a598234d#diff-22ca66176c6879ee3daf6f501b7311570793d61040a177b2ed0ea289d558744eR1-R72" rel="noopener noreferrer"&gt;GitHub link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you need help integrating emailing or environment management in your project, let me know.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>fastapi</category>
      <category>smtp</category>
    </item>
    <item>
      <title>Leveling Up My Task Automation API: Models, Routes, and Scheduling</title>
      <dc:creator>Dillion Huston</dc:creator>
      <pubDate>Fri, 01 Aug 2025 12:10:05 +0000</pubDate>
      <link>https://dev.to/dillionhuston/leveling-up-my-task-automation-api-models-routes-and-scheduling-4llb</link>
      <guid>https://dev.to/dillionhuston/leveling-up-my-task-automation-api-models-routes-and-scheduling-4llb</guid>
      <description>&lt;p&gt;Hey DEV community, I’m excited to share some fresh updates I pushed to my &lt;strong&gt;Task Automation API&lt;/strong&gt; in &lt;a href="https://github.com/dillionhuston/Task-Automation-API/commit/114bbb85bad9ce1affaea44c4a30af4d06ec455e" rel="noopener noreferrer"&gt;this commit&lt;/a&gt;. This one’s all about getting the task model, routes, and scheduling logic in shape, setting the stage for a solid task management system. If you liked my &lt;a href="https://dev.to/dillionhuston/what-are-http-status-codes-and-why-do-they-matter-15ia"&gt;HTTP status codes post&lt;/a&gt;, you’ll dig this dive into building a practical API. Let’s break it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s New in This Commit?
&lt;/h2&gt;

&lt;p&gt;This commit (&lt;a href="https://github.com/dillionhuston/Task-Automation-API/commit/114bbb85bad9ce1affaea44c4a30af4d06ec455e" rel="noopener noreferrer"&gt;114bbb8&lt;/a&gt;) lays down the foundation for managing tasks. Here’s the quick rundown:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Task Model&lt;/strong&gt;: Upgraded it with clean, reliable fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Routes&lt;/strong&gt;: Added endpoints to schedule, list, and cancel tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduling Logic&lt;/strong&gt;: Got tasks saving to the database smoothly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task Types&lt;/strong&gt;: Set up support for reminders and file cleanup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation&lt;/strong&gt;: Used Pydantic to keep scheduling times on point.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s take a closer look at what’s cooking.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Task Model Upgrade (&lt;code&gt;app/models/tasks.py&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;I gave the &lt;code&gt;TaskModel&lt;/code&gt; in &lt;code&gt;app/models/tasks.py&lt;/code&gt; a serious tune-up to make it robust and ready for action. Here’s what changed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;UUID for IDs&lt;/strong&gt;: Switched to &lt;code&gt;uuid.uuid4()&lt;/code&gt; for unique task IDs to avoid any overlap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Fields&lt;/strong&gt;: Refined &lt;code&gt;user_id&lt;/code&gt;, &lt;code&gt;task_type&lt;/code&gt;, &lt;code&gt;schedule_time&lt;/code&gt;, and &lt;code&gt;status&lt;/code&gt; with SQLAlchemy, adding constraints like &lt;code&gt;nullable=False&lt;/code&gt; for required fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timezone Support&lt;/strong&gt;: Added a &lt;code&gt;utcnow()&lt;/code&gt; function to ensure &lt;code&gt;schedule_time&lt;/code&gt; uses UTC, keeping things consistent across timezones.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s the updated code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy.orm&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;relationship&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy.ext.declarative&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;declarative_base&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt;

&lt;span class="n"&gt;Base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;declarative_base&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;utcnow&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;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="n"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utc&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;TaskModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;__tablename__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tasks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;primary_key&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;index&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;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;users.id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;nullable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;task_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nullable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;schedule_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timezone&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;nullable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nullable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scheduled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This model is now set to handle tasks.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. New Routes for Task Management (&lt;code&gt;app/routers/tasks.py&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;I added some key endpoints in &lt;code&gt;app/routers/tasks.py&lt;/code&gt; to make the API functional:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Schedule a Task (&lt;code&gt;POST /schedule&lt;/code&gt;)&lt;/strong&gt;: Lets users create and schedule tasks, validated with Pydantic’s &lt;code&gt;TaskCreate&lt;/code&gt; schema.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;List Tasks (&lt;code&gt;GET /list_files&lt;/code&gt;)&lt;/strong&gt;: Pulls up all tasks for the logged-in user. (Heads-up: &lt;code&gt;list_files&lt;/code&gt; is a naming oops—I’ll rename it to &lt;code&gt;list_tasks&lt;/code&gt; soon.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cancel a Task (&lt;code&gt;GET /cancel/{task_id}&lt;/code&gt;)&lt;/strong&gt;: Updates a task’s status to “cancelled” to ditch it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s the code:&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;APIRouter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app.routers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_current_user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TaskModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app.schemas.Tasks&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TaskCreate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TaskResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TaskStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TaskType&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app.utils.task&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;schedule_task&lt;/span&gt;

&lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;APIRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@router.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;/schedule&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;schedule_logic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TaskCreate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_db&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="nb"&gt;dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_current_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;new_task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;schedule_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&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="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;task&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;TaskResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&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="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nd"&gt;@router.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;/list_files&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="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;TaskResponse&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;list_tasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_db&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="nb"&gt;dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_current_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TaskModel&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TaskModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&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="n"&gt;tasks&lt;/span&gt;

&lt;span class="nd"&gt;@router.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;/cancel/{task_id}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;TaskResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cancel_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_db&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="nb"&gt;dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_current_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TaskModel&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TaskModel&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;task_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TaskModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&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="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;task&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;task doesnt exist or cant be found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cancelled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;db&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="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&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;task&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These routes are locked down with authentication and handle database operations cleanly. I’m also using HTTP status codes (like 400 for errors), tying back to my &lt;a href="https://dev.to/dillionhuston/what-are-http-status-codes-and-why-do-they-matter-15ia"&gt;HTTP status codes post&lt;/a&gt; for clear error communication.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Scheduling Logic and Task Types
&lt;/h2&gt;

&lt;p&gt;The commit includes scheduling logic (in &lt;code&gt;app/utils/task.py&lt;/code&gt;, not shown in the diff) that saves tasks to the database. I also added support for two task types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reminders&lt;/strong&gt;: For notifying users at a specific time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File Cleanup&lt;/strong&gt;: For deleting files (still in progress).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pydantic validation ensures scheduling times make sense, so no one’s trying to schedule a task for last week.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. What’s Next?
&lt;/h2&gt;

&lt;p&gt;This commit gets the API in a good spot, but there’s more to do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Task Execution&lt;/strong&gt;: Need to implement the actual logic for reminders and file deletion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix Naming&lt;/strong&gt;: &lt;code&gt;list_files&lt;/code&gt; should be &lt;code&gt;list_tasks&lt;/code&gt;—my bad.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Errors&lt;/strong&gt;: Plan to make error messages more specific.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduler Integration&lt;/strong&gt;: Looking at tools like APScheduler or Celery to run tasks on schedule.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;This commit is a big step toward making the Task Automation API a practical tool for managing tasks, whether it’s reminders or cleaning up files. It’s built with FastAPI and SQLAlchemy, keeping things clean and scalable. If you’re into APIs or automation, this might spark some ideas for your own projects.&lt;/p&gt;

&lt;p&gt;Check out the full commit &lt;a href="https://github.com/dillionhuston/Task-Automation-API/commit/114bbb85bad9ce1affaea44c4a30af4d06ec455e" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Got thoughts or suggestions? Drop them in the comments—I’d love to hear what you think!&lt;/p&gt;

&lt;p&gt;Happy coding!!&lt;/p&gt;

</description>
      <category>python</category>
      <category>api</category>
      <category>automation</category>
      <category>fastapi</category>
    </item>
    <item>
      <title>Building a User Authentication and File Management API with FastAPI</title>
      <dc:creator>Dillion Huston</dc:creator>
      <pubDate>Sun, 27 Jul 2025 14:41:07 +0000</pubDate>
      <link>https://dev.to/dillionhuston/building-a-user-authentication-and-file-management-api-with-fastapi-5al</link>
      <guid>https://dev.to/dillionhuston/building-a-user-authentication-and-file-management-api-with-fastapi-5al</guid>
      <description>&lt;p&gt;Over the past two weeks, I’ve been working on a backend API project using FastAPI. The goal is to build a solid foundation for user authentication and a file management system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Week 1: User Authentication System
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Initialized a FastAPI project with virtualenv and managed dependencies in requirements.txt.&lt;/li&gt;
&lt;li&gt;Configured environment variables with python-dotenv for things like &lt;code&gt;SECRET_KEY&lt;/code&gt; and &lt;code&gt;DATABASE_URL&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Created the User model using SQLAlchemy with fields including &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, &lt;code&gt;hashed_password&lt;/code&gt;, and status flags.&lt;/li&gt;
&lt;li&gt;Implemented JWT-based authentication including user registration, login, and token refresh.&lt;/li&gt;
&lt;li&gt;Built user endpoints (&lt;code&gt;/register&lt;/code&gt;, &lt;code&gt;/login&lt;/code&gt;, &lt;code&gt;/me&lt;/code&gt;) for managing user actions.&lt;/li&gt;
&lt;li&gt;Added dependency injection for database sessions and authentication in the routes.&lt;/li&gt;
&lt;li&gt;Wrote basic tests for authentication endpoints.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the end of week one, the API supports user registration and login, returning JWT tokens for authorized access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Week 2: File Management System
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Added a File model linked to users, storing file metadata such as filename, hash, and upload date.&lt;/li&gt;
&lt;li&gt;Created file endpoints to upload, list, and delete files (&lt;code&gt;/upload&lt;/code&gt;, &lt;code&gt;/list&lt;/code&gt;, &lt;code&gt;/delete/{file_id}&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Handled file uploads with python-multipart, storing files on disk using unique filenames.&lt;/li&gt;
&lt;li&gt;Computed and stored SHA-256 hashes for uploaded files to ensure integrity.&lt;/li&gt;
&lt;li&gt;Restricted file access based on user authentication, enforcing ownership rules.&lt;/li&gt;
&lt;li&gt;Implemented validation for file size and allowed extensions.&lt;/li&gt;
&lt;li&gt;Started writing tests for the file management functionality.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;Moving forward, I plan to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enhance file validation and error handling.&lt;/li&gt;
&lt;li&gt;Add support for user roles and permissions.&lt;/li&gt;
&lt;li&gt;Integrate background tasks for file maintenance using Celery.&lt;/li&gt;
&lt;li&gt;Improve test coverage and add documentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it out
&lt;/h2&gt;

&lt;p&gt;The project is open source and available on GitHub: &lt;a href="https://github.com/dillionhuston/Task-Automation-API" rel="noopener noreferrer"&gt;Task Automation API&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback and contributions are welcome.&lt;/p&gt;




&lt;p&gt;If you’re interested in backend APIs, FastAPI is a great framework that makes building async, secure APIs straightforward. This project is a good way to practice authentication, file handling, and database relationships.&lt;/p&gt;




&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>fastapi</category>
      <category>python</category>
      <category>backend</category>
      <category>jwt</category>
    </item>
    <item>
      <title>What I’ve Been Working On Lately: Networking Tools and JWT Auth</title>
      <dc:creator>Dillion Huston</dc:creator>
      <pubDate>Sat, 05 Jul 2025 12:36:16 +0000</pubDate>
      <link>https://dev.to/dillionhuston/what-ive-been-working-on-lately-networking-tools-and-jwt-auth-5bg</link>
      <guid>https://dev.to/dillionhuston/what-ive-been-working-on-lately-networking-tools-and-jwt-auth-5bg</guid>
      <description>&lt;p&gt;Over the last few weeks, I’ve been keeping things simple and focused: building small networking tools and working on secure backend authentication with Flask. Thought I’d share a quick update for those of you following my journey (shoutout to all 812 of you).&lt;/p&gt;

&lt;h3&gt;
  
  
  Networking Tools
&lt;/h3&gt;

&lt;p&gt;Most of my recent project time has gone into understanding networking at a deeper level — not just from a textbook or video, but by building tools that interact with the network directly.&lt;/p&gt;

&lt;p&gt;Here’s what I’ve worked on so far:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A basic &lt;strong&gt;port scanner&lt;/strong&gt; written in Python
&lt;/li&gt;
&lt;li&gt;A script to send &lt;strong&gt;ARP requests&lt;/strong&gt; and identify devices on the local network
&lt;/li&gt;
&lt;li&gt;Learning how data moves through different layers of the TCP/IP stack
&lt;/li&gt;
&lt;li&gt;Writing code that deals directly with packets and interfaces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This kind of low-level work has helped me build a stronger intuition for how systems talk to each other — something that really improves everything else I do in backend development.&lt;/p&gt;

&lt;h3&gt;
  
  
  JWT Authentication with Flask
&lt;/h3&gt;

&lt;p&gt;On the web backend side, I’ve been working on setting up &lt;strong&gt;JWT (JSON Web Token) authentication&lt;/strong&gt; in a Flask API.&lt;/p&gt;

&lt;p&gt;Things I’ve been learning and implementing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Issuing and verifying tokens securely&lt;/li&gt;
&lt;li&gt;Protecting routes and controlling access based on token roles&lt;/li&gt;
&lt;li&gt;Structuring the app with Flask blueprints, SQLAlchemy, and proper config separation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is laying the groundwork for future tools and APIs I want to build — where users can log in, store data securely, and interact with the backend in a clean, secure way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s Talk
&lt;/h3&gt;

&lt;p&gt;If you’ve been following my posts, I’d love to hear from you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Want me to share one of the tools? Let me know.&lt;/li&gt;
&lt;li&gt;Curious how I’m handling JWT or structuring the API? Ask and I’ll post more details.&lt;/li&gt;
&lt;li&gt;Also happy to chat if you’re working on anything similar — whether it’s low-level networking or backend auth systems.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Thanks for following along. More updates coming soon.&lt;/p&gt;

</description>
      <category>networking</category>
      <category>flask</category>
      <category>jwt</category>
      <category>python</category>
    </item>
    <item>
      <title>What Are HTTP Status Codes and Why Do They Matter?</title>
      <dc:creator>Dillion Huston</dc:creator>
      <pubDate>Sun, 25 May 2025 14:08:38 +0000</pubDate>
      <link>https://dev.to/dillionhuston/what-are-http-status-codes-and-why-do-they-matter-15ia</link>
      <guid>https://dev.to/dillionhuston/what-are-http-status-codes-and-why-do-they-matter-15ia</guid>
      <description>&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%2Fqe6m7gp9g4qkak2z9rmh.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%2Fqe6m7gp9g4qkak2z9rmh.png" alt="Image description" width="348" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’ve ever built a web app or worked with an API, you’ve probably seen things like 404 or 500 pop up. These numbers might seem like errors — and sometimes they are — but they’re actually just how servers communicate what’s going on.&lt;/p&gt;

&lt;p&gt;In this post, we’ll walk through what HTTP status codes are, what the common ones mean, and why you should care about them as a developer.&lt;/p&gt;




&lt;h2&gt;
  
  
  So, what &lt;em&gt;is&lt;/em&gt; a status code?
&lt;/h2&gt;

&lt;p&gt;Whenever your browser or app sends a request to a server (like loading a webpage or submitting a form), the server sends back a response. Part of that response includes a status code — a three-digit number that gives a quick summary of what happened.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;200&lt;/code&gt; means “everything went fine”&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;404&lt;/code&gt; means “the thing you asked for doesn’t exist”&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;500&lt;/code&gt; means “something broke on the server”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These codes are standardized and fall into five categories.&lt;/p&gt;




&lt;h2&gt;
  
  
  The different types (quick overview)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1xx – Just letting you know
&lt;/h3&gt;

&lt;p&gt;These are informational. You’ll rarely see them directly, unless you’re digging deep into HTTP-level stuff.&lt;/p&gt;




&lt;h3&gt;
  
  
  2xx – Success
&lt;/h3&gt;

&lt;p&gt;These are good. They mean the request worked.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;200 OK&lt;/code&gt; – Basic success.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;201 Created&lt;/code&gt; – Something was successfully created (like a new user).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;204 No Content&lt;/code&gt; – Success, but there’s no data to send back.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3xx – Redirects
&lt;/h3&gt;

&lt;p&gt;The server is telling the client to look somewhere else.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;301 Moved Permanently&lt;/code&gt; – The resource has moved and it’s not coming back.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;302 Found&lt;/code&gt; – Temporary redirect.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;304 Not Modified&lt;/code&gt; – The client already has the latest version, no need to download again.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4xx – You messed up (client error)
&lt;/h3&gt;

&lt;p&gt;These usually mean there’s something wrong with the request.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;400 Bad Request&lt;/code&gt; – Malformed request.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;401 Unauthorized&lt;/code&gt; – You need to log in.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;403 Forbidden&lt;/code&gt; – You’re logged in, but not allowed to access this.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;404 Not Found&lt;/code&gt; – The resource doesn't exist.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;429 Too Many Requests&lt;/code&gt; – Slow down, you’re sending too many requests too quickly.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  5xx – We messed up (server error)
&lt;/h3&gt;

&lt;p&gt;These mean the server failed to handle the request.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;500 Internal Server Error&lt;/code&gt; – A general error on the server.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;502 Bad Gateway&lt;/code&gt; – The server got an invalid response from another server.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;503 Service Unavailable&lt;/code&gt; – The server is temporarily overloaded or down.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why should you care?
&lt;/h2&gt;

&lt;p&gt;If you’re building or using an API, handling status codes properly helps everything run more smoothly. It gives your frontend clear information about what went wrong (or right), and it makes debugging a lot easier.&lt;/p&gt;

&lt;p&gt;For example, if your app gets a &lt;code&gt;403&lt;/code&gt;, you know it’s a permission issue. If it gets a &lt;code&gt;500&lt;/code&gt;, it’s probably something on the server that needs fixing.&lt;/p&gt;

&lt;p&gt;It also helps when writing error handling code — you don’t want to treat every error the same.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to practice
&lt;/h2&gt;

&lt;p&gt;If you want to get better at this, try writing a simple API in something like Flask, Express, or Django. Send different types of requests and play with returning different status codes.&lt;/p&gt;

&lt;p&gt;It’s one of those small things that makes you look like you know what you’re doing — and it’ll save you time when things break.&lt;/p&gt;




&lt;p&gt;Let me know if you want a follow-up post on how to handle these codes in your own app logic, or how to structure proper error responses.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
