<?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: Alejandro Tacoronte González</title>
    <description>The latest articles on DEV Community by Alejandro Tacoronte González (@alejandrotg-code).</description>
    <link>https://dev.to/alejandrotg-code</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3616093%2F70ea9956-c97f-45cb-a939-15081bbaf483.png</url>
      <title>DEV Community: Alejandro Tacoronte González</title>
      <link>https://dev.to/alejandrotg-code</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alejandrotg-code"/>
    <language>en</language>
    <item>
      <title>Secure Your FastAPI App in 3 Lines of Code (Without Breaking Swagger UI)</title>
      <dc:creator>Alejandro Tacoronte González</dc:creator>
      <pubDate>Mon, 28 Sep 2026 14:05:00 +0000</pubDate>
      <link>https://dev.to/alejandrotg-code/secure-your-fastapi-app-in-3-lines-of-code-without-breaking-swagger-ui-al6</link>
      <guid>https://dev.to/alejandrotg-code/secure-your-fastapi-app-in-3-lines-of-code-without-breaking-swagger-ui-al6</guid>
      <description>&lt;p&gt;Setting standard HTTP security headers—such as &lt;code&gt;Content-Security-Policy&lt;/code&gt; (CSP), &lt;code&gt;Strict-Transport-Security&lt;/code&gt; (HSTS), and &lt;code&gt;X-Frame-Options&lt;/code&gt;—is standard practice before shipping an API to production. They protect your users and infrastructure against common web vulnerabilities like clickjacking, MIME-type sniffing, cross-site scripting (XSS), and cross-origin resource leaks.&lt;/p&gt;

&lt;p&gt;However, in FastAPI, developers routinely hit a frustrating roadblock the moment they attempt to enforce a strict Content Security Policy:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FastAPI's interactive documentation (&lt;code&gt;/docs&lt;/code&gt; and &lt;code&gt;/redoc&lt;/code&gt;) breaks immediately.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The interactive docs rely heavily on inline script execution, stylesheets, and remote assets to render Swagger UI and ReDoc properly on page load. When you add a generic, restrictive CSP middleware, the browser enforces the directives strictly, blocks those assets, and leaves you with a blank page. Developers typically end up wasting hours tuning directives by trial and error, or worse, abandoning CSP entirely.&lt;/p&gt;

&lt;p&gt;To solve this problem cleanly, I built &lt;a href="https://github.com/aletgdev/fastapi-security-headers" rel="noopener noreferrer"&gt;&lt;strong&gt;fastapi-security-headers&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;




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

&lt;p&gt;Many existing security header packages for Python web frameworks either wrap requests with high-level Starlette abstractions, buffer full response bodies into memory, or introduce unnecessary third-party dependencies into your dependency tree.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fastapi-security-headers&lt;/code&gt; was designed to be as minimal, direct, and efficient as possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pure ASGI:&lt;/strong&gt; Operates directly at the ASGI specification level. It intercepts the &lt;code&gt;http.response.start&lt;/code&gt; message and injects headers directly into the stream without buffering payloads or wrapping request/response objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pre-encoded Bytes:&lt;/strong&gt; Headers are processed and encoded into raw &lt;code&gt;tuple[bytes, bytes]&lt;/code&gt; structures once during application initialization. At runtime, injecting headers into a response involves virtually zero compute overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero External Dependencies:&lt;/strong&gt; Built strictly using Python's standard library (&lt;code&gt;dataclasses&lt;/code&gt;, &lt;code&gt;typing&lt;/code&gt;). It will never bloat your &lt;code&gt;poetry.lock&lt;/code&gt; or &lt;code&gt;requirements.txt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs-Aware Presets:&lt;/strong&gt; Ships with tested presets that enforce strict CSP policies while granting the precise exemptions needed for Swagger UI and ReDoc to work out of the box.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safe for Streams and WebSockets:&lt;/strong&gt; Automatically avoids interfering with &lt;code&gt;StreamingResponse&lt;/code&gt;, Server-Sent Events (SSE), or WebSocket connections.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Route-Aware Precedence:&lt;/strong&gt; Honors explicit headers set by individual route handlers, only filling in missing security policies rather than blindly overwriting endpoint behavior.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Install the package via &lt;code&gt;pip&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Quickstart: Securing Your API and Docs
&lt;/h2&gt;

&lt;p&gt;The fastest way to secure an API while keeping the documentation intact is using the built-in &lt;code&gt;swagger_friendly&lt;/code&gt; preset:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi_security_headers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SecurityHeadersMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Presets&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;Secure Production API&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;docs_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/docs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;redoc_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/redoc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Apply baseline security headers + Swagger/ReDoc compatible CSP
&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;SecurityHeadersMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Presets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;swagger_friendly&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&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;/&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;root&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;healthy&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;security&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;enforced&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.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;/items/{item_id}&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_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_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="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;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;item_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Item &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item_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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this single middleware configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every standard API endpoint receives strict transport and isolation headers.&lt;/li&gt;
&lt;li&gt;Visiting &lt;code&gt;/docs&lt;/code&gt; or &lt;code&gt;/redoc&lt;/code&gt; loads all necessary scripts, styles, and assets without generating CSP violations in the browser console.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Default Baseline Headers
&lt;/h2&gt;

&lt;p&gt;When using &lt;code&gt;fastapi-security-headers&lt;/code&gt;, every response is protected with the following baseline headers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;HTTP Header&lt;/th&gt;
&lt;th&gt;Default Value&lt;/th&gt;
&lt;th&gt;Security Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;X-Content-Type-Options&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nosniff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;MIME-Sniffing:&lt;/strong&gt; Prevents browsers from guessing content types, stopping executable payloads disguised as non-executable types like images or JSON.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;X-Frame-Options&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DENY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Clickjacking:&lt;/strong&gt; Disallows any domain from rendering your site inside an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;, preventing UI redressing attacks.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;X-XSS-Protection&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Auditor Exploits:&lt;/strong&gt; Disables legacy browser XSS filters that have been demonstrated to introduce new vulnerabilities (per modern OWASP guidelines).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Strict-Transport-Security&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;max-age=31536000; includeSubDomains&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;SSL Stripping / MitM:&lt;/strong&gt; Instructs browsers to communicate exclusively over HTTPS for the next 12 months, including all subdomains.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Referrer-Policy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;strict-origin-when-cross-origin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Data Leakage:&lt;/strong&gt; Sends the full URL only for same-origin requests; strips query strings and paths when navigating across origins.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Permissions-Policy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;geolocation=(), microphone=(), camera=()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Feature Abuse:&lt;/strong&gt; Explicitly restricts client browsers from invoking unused device hardware APIs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Cross-Origin-Opener-Policy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;same-origin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Spectre / Process Isolation:&lt;/strong&gt; Isolates your browsing context from cross-origin windows, preventing malicious document references.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Cross-Origin-Resource-Policy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;same-origin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Cross-Origin Reads:&lt;/strong&gt; Prevents unauthorized origins from loading your API responses as resources.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Built-In Presets
&lt;/h2&gt;

&lt;p&gt;Different workloads have different requirements. You can choose between pre-configured presets depending on what your service exposes:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Swagger-Friendly Preset (&lt;code&gt;Presets.swagger_friendly()&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Designed for services that serve interactive documentation. It configures a Content Security Policy that permits assets required by Swagger UI and ReDoc while keeping all other resource vectors locked down:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi_security_headers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SecurityHeadersMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Presets&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;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;SecurityHeadersMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Presets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;swagger_friendly&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Headless API Preset (&lt;code&gt;Presets.api()&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Ideal for pure JSON microservices, internal services, or mobile backends that do not expose any HTML UI:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi_security_headers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SecurityHeadersMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Presets&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;docs_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;redoc_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Restricts default-src to 'none' across all resource types
&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;SecurityHeadersMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Presets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;api&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This enforces &lt;code&gt;Content-Security-Policy: default-src 'none'&lt;/code&gt;, disallowing any browser execution of scripts, styles, frames, or plugins.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Strict Preset (&lt;code&gt;Presets.strict()&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Intended for high-compliance applications (such as financial, enterprise, or healthcare software subject to PCI-DSS, SOC 2, or HIPAA):&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi_security_headers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SecurityHeadersMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Presets&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="c1"&gt;# Enforces 2-year HSTS with preload flag and strict framing constraints
&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;SecurityHeadersMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Presets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Custom Configuration
&lt;/h2&gt;

&lt;p&gt;If you have specific architectural requirements or need to define custom policies, you can instantiate &lt;code&gt;SecurityConfig&lt;/code&gt; directly:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi_security_headers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SecurityHeadersMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SecurityConfig&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;custom_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SecurityConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;enable_hsts&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;hsts_max_age&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;63072000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# 2 years
&lt;/span&gt;    &lt;span class="n"&gt;hsts_include_subdomains&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;hsts_preload&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;content_security_policy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default-src &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;self&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;img-src &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;self&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; data: https://images.example.com; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;script-src &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;self&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;frame-ancestors &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;none&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="n"&gt;custom_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;X-Permitted-Cross-Domain-Policies&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;none&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;Clear-Site-Data&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;cache&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="s"&gt;cookies&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="s"&gt;storage&lt;/span&gt;&lt;span class="sh"&gt;"'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;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;SecurityHeadersMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;custom_config&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Verifying Headers
&lt;/h2&gt;

&lt;p&gt;You can verify that the headers are properly applied using &lt;code&gt;curl&lt;/code&gt; against your local or staging server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; http://localhost:8000/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;
&lt;span class="na"&gt;content-type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;
&lt;span class="na"&gt;x-content-type-options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nosniff&lt;/span&gt;
&lt;span class="na"&gt;x-frame-options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DENY&lt;/span&gt;
&lt;span class="na"&gt;x-xss-protection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0&lt;/span&gt;
&lt;span class="na"&gt;strict-transport-security&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;max-age=31536000; includeSubDomains&lt;/span&gt;
&lt;span class="na"&gt;referrer-policy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;strict-origin-when-cross-origin&lt;/span&gt;
&lt;span class="na"&gt;permissions-policy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;geolocation=(), microphone=(), camera=()&lt;/span&gt;
&lt;span class="na"&gt;cross-origin-opener-policy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;same-origin&lt;/span&gt;
&lt;span class="na"&gt;cross-origin-resource-policy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;same-origin&lt;/span&gt;
&lt;span class="na"&gt;content-security-policy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default-src 'self'; script-src 'self' https://cdn.jsdelivr.net 'unsafe-inline'; style-src 'self' https://cdn.jsdelivr.net 'unsafe-inline'; img-src 'self' data: https://fastapi.tiangolo.com;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also submit your public URL to &lt;a href="https://securityheaders.com" rel="noopener noreferrer"&gt;securityheaders.com&lt;/a&gt; to audit your overall compliance grade.&lt;/p&gt;




&lt;h2&gt;
  
  
  Feedback &amp;amp; Source Code
&lt;/h2&gt;

&lt;p&gt;The library is completely open source under the MIT License.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/aletgdev/fastapi-security-headers" rel="noopener noreferrer"&gt;aletgdev/fastapi-security-headers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PyPI Package:&lt;/strong&gt; &lt;a href="https://pypi.org/project/fastapi-security-headers/" rel="noopener noreferrer"&gt;pypi.org/project/fastapi-security-headers&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you encounter any edge cases with custom documentation routes or want to suggest new presets, feel free to open an issue or start a discussion on GitHub.&lt;/p&gt;

</description>
      <category>python</category>
      <category>fastapi</category>
      <category>webdev</category>
      <category>security</category>
    </item>
    <item>
      <title>Game Recommended AI</title>
      <dc:creator>Alejandro Tacoronte González</dc:creator>
      <pubDate>Thu, 28 May 2026 19:22:00 +0000</pubDate>
      <link>https://dev.to/alejandrotg-code/game-recommended-ai-4h3m</link>
      <guid>https://dev.to/alejandrotg-code/game-recommended-ai-4h3m</guid>
      <description>&lt;p&gt;He desarrollado una plataforma web Full-Stack diseñada para analizar de forma inteligente el sentimiento real de la comunidad de jugadores en Steam antes de realizar una compra. El objetivo principal ha sido construir un producto funcional de principio a fin, desde el modelo de Machine Learning hasta el despliegue.&lt;/p&gt;

&lt;p&gt;🔧 Tecnologías utilizadas:&lt;br&gt;
• Backend: Python &amp;amp; FastAPI &lt;br&gt;
• IA / Machine Learning: Modelo de clasificación Naive Bayes (NLP) &lt;br&gt;
• Frontend: React, Tailwind CSS&lt;br&gt;
• Integraciones: Steam API&lt;/p&gt;

&lt;p&gt;📌 Funcionalidades principales:&lt;br&gt;
• Buscador predictivo: Autocompletado de juegos en tiempo real con portadas y precios extraídos de Steam. &lt;br&gt;
• Análisis de sentimiento con IA: Procesamiento automatizado de decenas de reseñas en español para predecir si el juego merece la pena. &lt;br&gt;
• Desglose estadístico: Visualización limpia de porcentajes de aprobación, contador de reseñas analizadas y filtrado inteligente.&lt;/p&gt;

&lt;p&gt;Este proyecto me ha permitido trabajar aspectos clave del desarrollo moderno como:&lt;br&gt;
• Despliegue e Infraestructura: Configuración de servidores web en producción. &lt;br&gt;
• Procesamiento de Lenguaje Natural (NLP): Implementación de lógica para la clasificación de textos.&lt;/p&gt;

&lt;p&gt;El proyecto ya está completamente desplegado, funcionando y listo para probarse en vivo.&lt;/p&gt;

&lt;p&gt;¡Cualquier feedback es más que bienvenido! 🙌&lt;/p&gt;

&lt;p&gt;Demo: &lt;a href="https://game-recommended.alejandrotg.es/" rel="noopener noreferrer"&gt;https://game-recommended.alejandrotg.es/&lt;/a&gt;&lt;br&gt;
Github: &lt;a href="https://github.com/alejandrotg-code" rel="noopener noreferrer"&gt;https://github.com/alejandrotg-code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>spanish</category>
      <category>python</category>
    </item>
    <item>
      <title>🎧 Expanding the GTZAN Dataset: A Journey from YouTube to Mel Spectrograms</title>
      <dc:creator>Alejandro Tacoronte González</dc:creator>
      <pubDate>Fri, 24 Apr 2026 11:08:42 +0000</pubDate>
      <link>https://dev.to/alejandrotg-code/expanding-the-gtzan-dataset-a-journey-from-youtube-to-mel-spectrograms-74k</link>
      <guid>https://dev.to/alejandrotg-code/expanding-the-gtzan-dataset-a-journey-from-youtube-to-mel-spectrograms-74k</guid>
      <description>&lt;p&gt;I am currently finishing my specialization in Artificial Intelligence and Big Data, and I’ve decided to document the progress of my final project. This work integrates everything I’ve learned in the modules of AI Models (Modelos de Inteligencia Artificial) and Machine Learning Systems (Sistemas de Aprendizaje Automático).&lt;/p&gt;

&lt;p&gt;The goal? A robust Music Genre Classifier. But as any data scientist will tell you, the model is only as good as the data. Today, I focused on building the "Data Kitchen": the pipeline that fetches, cleans, and prepares audio for training.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. The Challenge: Expanding the GTZAN Dataset&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;While the &lt;strong&gt;GTZAN dataset&lt;/strong&gt; is the industry standard, it lacks modern genres. To make my project unique, I wanted to include Lofi and Rap another others.&lt;/p&gt;

&lt;p&gt;I used &lt;code&gt;yt-dlp&lt;/code&gt; to source high-quality audio from YouTube. However, I ran into a classic "Junior vs. Environment" boss fight: FFmpeg.&lt;/p&gt;

&lt;p&gt;Technical Tip: Even if you install FFmpeg via Conda, Windows sometimes hides the binaries from your Python subprocesses. I solved this by explicitly mapping the ffmpeg_location in my script to ensure the conversion to .wav never fails.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;2. Standardizing for Machine Learning Systems&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In our Machine Learning Systems module, we emphasized that consistency is key. To make my new data compatible with GTZAN, I had to "clone" its technical specifications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Sample Rate: 22,050 Hz.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Channels: Mono.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Duration: Exactly 30-second segments.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I developed a script that takes a 1-hour "Lofi Study Beats" mix and slices it into perfect 30-second chunks, maintaining a strict naming convention: lofi.00000.wav, lofi.00001.wav, etc. This ensures the data is ready for bulk processing without manual intervention.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;3. Feature Extraction: The Mel Spectrogram&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For the &lt;strong&gt;AI Models&lt;/strong&gt; part of the project, we aren't just "listening" to the audio—we are "seeing" it. Using librosa, I transform the raw waveforms into &lt;strong&gt;Mel Spectrograms&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The Mel scale is vital because it represents frequencies the way humans actually perceive them. It turns a complex audio signal into a 2D image, allowing me to use &lt;strong&gt;Convolutional Neural Networks (CNNs)&lt;/strong&gt; to identify patterns, like the low-pass filters typical of Lofi or the sharp transients in Rap.&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%2Fpope87rgyayxqmtp5udj.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%2Fpope87rgyayxqmtp5udj.png" alt="Mel Spectogram of Lofi" width="387" height="385"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;4. Key Takeaways for Fellow Students&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Relative Paths are Dangerous:&lt;/strong&gt; When running scripts from the terminal, ../data might point to nowhere. I switched to Path(&lt;strong&gt;file&lt;/strong&gt;).resolve() to make my project portable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Validation:&lt;/strong&gt; GTZAN has a famous corrupt file (jazz.00054.wav). Learning to handle these exceptions programmatically is a crucial skill I've sharpened during this project.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Next Steps
&lt;/h3&gt;

&lt;p&gt;The pipeline is clean. The data is standardized. The next phase of my final project involves designing the CNN architecture and beginning the long-awaited training phase.&lt;/p&gt;

&lt;p&gt;Are you a student or a pro in AI? How do you handle your audio preprocessing pipelines? Let’s discuss in the comments!&lt;/p&gt;

</description>
      <category>python</category>
      <category>machinelearning</category>
      <category>datascience</category>
      <category>learning</category>
    </item>
    <item>
      <title>Building a Movie Recommendation API with Spring Boot 🎬</title>
      <dc:creator>Alejandro Tacoronte González</dc:creator>
      <pubDate>Sat, 14 Mar 2026 12:30:09 +0000</pubDate>
      <link>https://dev.to/alejandrotg-code/building-a-movie-recommendation-api-with-spring-boot-162b</link>
      <guid>https://dev.to/alejandrotg-code/building-a-movie-recommendation-api-with-spring-boot-162b</guid>
      <description>&lt;p&gt;Recently I built a backend API for a movie and TV show recommendation platform using &lt;strong&gt;Java and Spring Boot&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The goal of the project was to practice designing a &lt;strong&gt;REST API&lt;/strong&gt;, implementing &lt;strong&gt;authentication&lt;/strong&gt;, and integrating an external API.&lt;/p&gt;




&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;The API includes several features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Search movies and TV shows using the TMDB API&lt;/li&gt;
&lt;li&gt;User authentication with JWT&lt;/li&gt;
&lt;li&gt;Save favorite movies and shows&lt;/li&gt;
&lt;li&gt;Rate content&lt;/li&gt;
&lt;li&gt;Get trending content&lt;/li&gt;
&lt;li&gt;RESTful API design&lt;/li&gt;
&lt;li&gt;API documentation using Swagger / OpenAPI&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Backend
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Java 21&lt;/li&gt;
&lt;li&gt;Spring Boot&lt;/li&gt;
&lt;li&gt;Spring Security&lt;/li&gt;
&lt;li&gt;JWT Authentication&lt;/li&gt;
&lt;li&gt;Spring Data JPA&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Database
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  External API
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;TMDB API (The Movie Database)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Documentation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Swagger / OpenAPI&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Example API Request
&lt;/h2&gt;

&lt;p&gt;Example request to get trending content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /content/trending
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"page"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"results"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"War Machine"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"release_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-02-12"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"vote_average"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7.1&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Project Architecture
&lt;/h2&gt;

&lt;p&gt;The application follows a layered architecture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Controller → Service → Repository → Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This structure helps keep the code organized and maintainable.&lt;/p&gt;




&lt;h2&gt;
  
  
  API Documentation
&lt;/h2&gt;

&lt;p&gt;The API is documented using &lt;strong&gt;Swagger / OpenAPI&lt;/strong&gt;, which makes it easy to explore and test the endpoints.&lt;/p&gt;




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

&lt;p&gt;While building this project I practiced several backend concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Designing REST APIs&lt;/li&gt;
&lt;li&gt;Implementing authentication with Spring Security&lt;/li&gt;
&lt;li&gt;Using JWT for authorization&lt;/li&gt;
&lt;li&gt;Integrating external APIs&lt;/li&gt;
&lt;li&gt;Structuring a backend project using layered architecture&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  GitHub Repository
&lt;/h2&gt;

&lt;p&gt;You can find the full project here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/alejandrotg-code/tv-and-movie-db" rel="noopener noreferrer"&gt;https://github.com/alejandrotg-code/tv-and-movie-db&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Feedback and suggestions are always welcome!&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>backend</category>
      <category>api</category>
    </item>
    <item>
      <title>My first contribution to an OpenSearch project: A Junior’s journey 🚀</title>
      <dc:creator>Alejandro Tacoronte González</dc:creator>
      <pubDate>Sat, 28 Feb 2026 12:30:42 +0000</pubDate>
      <link>https://dev.to/alejandrotg-code/my-first-contribution-to-an-opensearch-project-a-juniors-journey-3i8i</link>
      <guid>https://dev.to/alejandrotg-code/my-first-contribution-to-an-opensearch-project-a-juniors-journey-3i8i</guid>
      <description>&lt;h2&gt;
  
  
  🇺🇸 English Version
&lt;/h2&gt;

&lt;h2&gt;
  
  
  How it started
&lt;/h2&gt;

&lt;p&gt;Hello world! I'm Alejandro, a Junior Developer currently studying AI &amp;amp; Big Data. Like many beginners, I used to look at huge GitHub repositories (like those from Amazon or the Linux Foundation) with a mix of respect and fear. I thought: "I'm not ready to contribute there yet."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I was wrong.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yesterday, I made my first contribution to the &lt;code&gt;opensearch-agent-server&lt;/code&gt; project, managed by &lt;strong&gt;Mingshi Liu (@mingshl)&lt;/strong&gt;, a Machine Learning Engineer at &lt;strong&gt;AWS OpenSearch&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's not "just" a license
&lt;/h2&gt;

&lt;p&gt;My task was to add the &lt;strong&gt;Apache 2.0 LICENSE&lt;/strong&gt; file. You might think: &lt;em&gt;"That's not coding!"&lt;/em&gt;. But for a Junior, this was a masterclass in professional workflows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reading the Guidelines:&lt;/strong&gt; I had to study the &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DCO (Developer Certificate of Origin):&lt;/strong&gt; I learned that big companies require signed commits (&lt;code&gt;git commit -s&lt;/code&gt;) for legal safety.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Communication:&lt;/strong&gt; I had to interact in English with a Senior Engineer to get the task assigned.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The feeling
&lt;/h2&gt;

&lt;p&gt;Seeing an engineer from &lt;strong&gt;Amazon&lt;/strong&gt; say &lt;em&gt;"thanks for taking the initiative"&lt;/em&gt; and seeing my name in the "Assigned" section was a huge boost for my confidence. &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%2Fgx5w6d38lf710zdpkg7f.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%2Fgx5w6d38lf710zdpkg7f.png" alt="Assign Task" width="799" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnk2oqx5hffek5fkze51k.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%2Fnk2oqx5hffek5fkze51k.png" alt="Pull Request status" width="799" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My advice for Juniors:&lt;/strong&gt; Don't wait to be a Senior to contribute. Start with documentation, licenses, or small fixes. The community is waiting for you!&lt;/p&gt;




&lt;h2&gt;
  
  
  🇪🇸 Versión en Español
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Cómo empezó todo
&lt;/h2&gt;

&lt;p&gt;¡Hola a todos! Soy Alejandro, un desarrollador Junior estudiante de IA y Big Data. Como muchos principiantes, solía mirar los grandes repositorios de GitHub (como los de Amazon o la Fundación Linux) con una mezcla de respeto y miedo. Pensaba: "Todavía no estoy listo para contribuir ahí".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Estaba equivocado.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ayer hice mi primera contribución al proyecto &lt;code&gt;opensearch-agent-server&lt;/code&gt;, gestionado por &lt;strong&gt;Mingshi Liu (@mingshl)&lt;/strong&gt;, ingeniera de Machine Learning en &lt;strong&gt;AWS OpenSearch&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  No es "solo" una licencia
&lt;/h2&gt;

&lt;p&gt;Mi tarea fue añadir el archivo &lt;strong&gt;Apache 2.0 LICENSE&lt;/strong&gt;. Podrías pensar: &lt;em&gt;"¡Eso no es programar!"&lt;/em&gt;. Pero para un Junior, esto fue una clase magistral de flujos de trabajo profesionales:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Leer las reglas:&lt;/strong&gt; Tuve que estudiar el archivo &lt;code&gt;CONTRIBUTING.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DCO (Developer Certificate of Origin):&lt;/strong&gt; Aprendí que las grandes empresas exigen commits firmados (&lt;code&gt;git commit -s&lt;/code&gt;) por seguridad legal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comunicación:&lt;/strong&gt; Tuve que interactuar en inglés con una ingeniera Senior para que me asignaran la tarea.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  La sensación
&lt;/h2&gt;

&lt;p&gt;Ver a una ingeniera de &lt;strong&gt;Amazon&lt;/strong&gt; decir &lt;em&gt;"gracias por tomar la iniciativa"&lt;/em&gt; y ver mi nombre en la sección de "Asignado" fue un subidón de confianza increíble.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mi consejo para otros Juniors:&lt;/strong&gt; No esperes a ser Senior para contribuir. Empieza con documentación, licencias o errores pequeños. ¡La comunidad te está esperando!&lt;/p&gt;




&lt;h3&gt;
  
  
  Let's connect! / ¡Conectemos!
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/alejandrotg-code" rel="noopener noreferrer"&gt;alejandrotg-code&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/alejandrotacoronte/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/alejandrotacoronte/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>beginners</category>
      <category>spanish</category>
      <category>aws</category>
    </item>
    <item>
      <title>Looking for Advice as a Junior Fullstack Developer</title>
      <dc:creator>Alejandro Tacoronte González</dc:creator>
      <pubDate>Mon, 17 Nov 2025 18:50:08 +0000</pubDate>
      <link>https://dev.to/alejandrotg-code/looking-for-advice-as-a-junior-fullstack-developer-69n</link>
      <guid>https://dev.to/alejandrotg-code/looking-for-advice-as-a-junior-fullstack-developer-69n</guid>
      <description>&lt;h2&gt;
  
  
  Looking for Advice as a Junior Fullstack Developer (Java, Node.js, React)
&lt;/h2&gt;

&lt;p&gt;Hi everyone 👋,&lt;/p&gt;

&lt;p&gt;My name is Alejandro Tacoronte, and I completed my &lt;strong&gt;(Cross-Platform Application Development) studies in 2024&lt;/strong&gt;. I’m currently looking to grow as a &lt;strong&gt;junior fullstack developer&lt;/strong&gt; and would love to get advice from those with experience in the industry.&lt;/p&gt;

&lt;p&gt;I have experience and knowledge in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Java and Node.js
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; Some experience with React
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Databases:&lt;/strong&gt; SQL
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version Control:&lt;/strong&gt; Git
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve worked on projects during my studies and internships, and now I want to &lt;strong&gt;build my own projects that demonstrate my skills and ability to learn&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;💡 I’d love to ask the community:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What “mini projects” would you recommend for a junior fullstack developer to stand out?
&lt;/li&gt;
&lt;li&gt;Which technologies or frameworks are most relevant in 2025?
&lt;/li&gt;
&lt;li&gt;Any advice on how to showcase skills effectively, even without years of professional experience?
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’d greatly appreciate any tips, resources, or personal experiences. 🙏  &lt;/p&gt;

&lt;p&gt;Thanks for reading! I’m looking forward to sharing my progress and learning alongside you all.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>career</category>
      <category>portfolio</category>
    </item>
  </channel>
</rss>
