<?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: Renzo Fernando LOYOLA VILCA CHOQUE</title>
    <description>The latest articles on DEV Community by Renzo Fernando LOYOLA VILCA CHOQUE (@renzo_fernandoloyolavil).</description>
    <link>https://dev.to/renzo_fernandoloyolavil</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%2F3644593%2F4ed5bd1a-ec5d-46cc-85ce-f841031d5bb5.png</url>
      <title>DEV Community: Renzo Fernando LOYOLA VILCA CHOQUE</title>
      <link>https://dev.to/renzo_fernandoloyolavil</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/renzo_fernandoloyolavil"/>
    <language>en</language>
    <item>
      <title>Decoupling Domain from Persistence: Implementing the Repository Pattern in Python</title>
      <dc:creator>Renzo Fernando LOYOLA VILCA CHOQUE</dc:creator>
      <pubDate>Wed, 24 Jun 2026 21:51:51 +0000</pubDate>
      <link>https://dev.to/renzo_fernandoloyolavil/decoupling-domain-from-persistence-implementing-the-repository-pattern-in-python-2jcb</link>
      <guid>https://dev.to/renzo_fernandoloyolavil/decoupling-domain-from-persistence-implementing-the-repository-pattern-in-python-2jcb</guid>
      <description>&lt;p&gt;Introduction and Context&lt;br&gt;
In enterprise applications, one of the most common anti-patterns is mixing business rules (Domain Logic) with database queries (Persistence Logic). As your application grows, this practice leads to highly coupled, fragile, and hard-to-test code.&lt;/p&gt;

&lt;p&gt;In his seminal book Patterns of Enterprise Application Architecture (PofEAA), Martin Fowler defines the Repository pattern as a mediator between the domain and data mapping layers, acting like an in-memory collection of domain objects.&lt;/p&gt;

&lt;p&gt;How Does the Repository Pattern Work?&lt;br&gt;
Instead of writing SQL queries or direct ORM calls inside your business services, you interact with an abstraction (an interface). The domain layer doesn’t know—and shouldn't care—whether the data comes from a PostgreSQL database, a local JSON file, or an external API. It simply requests or provides domain objects.&lt;/p&gt;

&lt;p&gt;Real-World Case Study: Academic Tutoring Management System&lt;br&gt;
Imagine we are building the backend for a university tutoring platform. We need to manage tutoring sessions without coupling our core business logic to a specific database engine.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Domain Entity (Pure Business Logic)
This class represents our core business domain. It is completely decoupled from any frameworks or database libraries.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Python&lt;/p&gt;

&lt;h1&gt;
  
  
  domain.py
&lt;/h1&gt;

&lt;p&gt;from datetime import datetime&lt;br&gt;
from dataclasses import dataclass&lt;/p&gt;

&lt;p&gt;@dataclass&lt;br&gt;
class TutoringSession:&lt;br&gt;
    id: str&lt;br&gt;
    student_id: str&lt;br&gt;
    tutor_id: str&lt;br&gt;
    date_time: datetime&lt;br&gt;
    subject: str&lt;br&gt;
    is_active: bool = True&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def cancel_session(self):
    if self.date_time &amp;lt; datetime.now():
        raise ValueError("Cannot cancel a session that has already occurred.")
    self.is_active = False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;The Repository Interface (Abstraction)
We define the contract that any concrete persistence mechanism must implement.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Python&lt;/p&gt;

&lt;h1&gt;
  
  
  repository_interface.py
&lt;/h1&gt;

&lt;p&gt;from abc import ABC, abstractmethod&lt;br&gt;
from typing import List, Optional&lt;br&gt;
from domain import TutoringSession&lt;/p&gt;

&lt;p&gt;class ITutoringRepository(ABC):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@abstractmethod
def save(self, session: TutoringSession) -&amp;gt; None:
    """Saves or updates a tutoring session."""
    pass

@abstractmethod
def find_by_id(self, session_id: str) -&amp;gt; Optional[TutoringSession]:
    """Retrieves a session by its unique identifier."""
    pass

@abstractmethod
def find_active_by_tutor(self, tutor_id: str) -&amp;gt; List[TutoringSession]:
    """Retrieves all active tutoring sessions for a specific tutor."""
    pass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;The Concrete Implementation (In-Memory for Infrastructure/Testing)
While you would use SQLAlchemy or a database client for production, the pattern allows us to create an in-memory version instantaneously for blazing-fast software testing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Python&lt;/p&gt;

&lt;h1&gt;
  
  
  in_memory_repository.py
&lt;/h1&gt;

&lt;p&gt;from typing import List, Optional, Dict&lt;br&gt;
from domain import TutoringSession&lt;br&gt;
from repository_interface import ITutoringRepository&lt;/p&gt;

&lt;p&gt;class InMemoryTutoringRepository(ITutoringRepository):&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self):&lt;br&gt;
        self._db: Dict[str, TutoringSession] = {}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def save(self, session: TutoringSession) -&amp;gt; None:
    self._db[session.id] = session

def find_by_id(self, session_id: str) -&amp;gt; Optional[TutoringSession]:
    return self._db.get(session_id)

def find_active_by_tutor(self, tutor_id: str) -&amp;gt; List[TutoringSession]:
    return [
        session for session in self._db.values()
        if session.tutor_id == tutor_id and session.is_active
    ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;The Service Layer (Use Case Execution)
Notice how the service consumes the repository interface without knowing how or where the data is actually stored.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Python&lt;/p&gt;

&lt;h1&gt;
  
  
  service.py
&lt;/h1&gt;

&lt;p&gt;from domain import TutoringSession&lt;br&gt;
from repository_interface import ITutoringRepository&lt;/p&gt;

&lt;p&gt;class TutoringService:&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self, repository: ITutoringRepository):&lt;br&gt;
        self.repository = repository&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def schedule_new_session(self, session: TutoringSession) -&amp;gt; None:
    # Complementary business logic validation
    current_sessions = self.repository.find_active_by_tutor(session.tutor_id)
    if len(current_sessions) &amp;gt;= 5:
        raise Exception("The tutor has already reached the maximum limit of active sessions.")

    self.repository.save(session)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Key Takeaways and Benefits&lt;br&gt;
Absolute Testability: You can unit test your TutoringService by passing the InMemoryTutoringRepository in milliseconds, without needing to spin up Docker containers or real databases.&lt;/p&gt;

&lt;p&gt;Substitutability: If you ever decide to migrate from a relational SQL database to a NoSQL engine or Firebase, your core business layer (service.py and domain.py) remains completely untouched. You simply write a new repository class that implements ITutoringRepository.&lt;/p&gt;

&lt;p&gt;🛠️ GitHub Repository Guide&lt;br&gt;
To make your repository look highly professional to your professor and research group, structure your project cleanly like this:&lt;/p&gt;

&lt;p&gt;Plaintext&lt;br&gt;
enterprise-patterns-repository/&lt;br&gt;
│&lt;br&gt;
├── src/&lt;br&gt;
│   ├── &lt;strong&gt;init&lt;/strong&gt;.py&lt;br&gt;
│   ├── domain.py&lt;br&gt;
│   ├── repository_interface.py&lt;br&gt;
│   ├── in_memory_repository.py&lt;br&gt;
│   └── service.py&lt;br&gt;
│&lt;br&gt;
├── main.py            # A small executable script demonstrating the workflow&lt;br&gt;
├── README.md          # Clear documentation on how to run the code&lt;br&gt;
└── .gitignore&lt;br&gt;
Inside your main.py, place a simple execution flow to showcase your pattern in action:&lt;/p&gt;

&lt;p&gt;Python&lt;br&gt;
from datetime import datetime&lt;br&gt;
from src.domain import TutoringSession&lt;br&gt;
from src.in_memory_repository import InMemoryTutoringRepository&lt;br&gt;
from src.service import TutoringService&lt;/p&gt;

&lt;p&gt;if &lt;strong&gt;name&lt;/strong&gt; == "&lt;strong&gt;main&lt;/strong&gt;":&lt;br&gt;
    # Initialize infrastructure and service layers&lt;br&gt;
    repo = InMemoryTutoringRepository()&lt;br&gt;
    service = TutoringService(repo)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create a domain object
new_session = TutoringSession(
    id="SES-001", 
    student_id="STUDENT-10", 
    tutor_id="TUTOR-05", 
    date_time=datetime(2026, 7, 1, 15, 0), 
    subject="Software Architecture Patterns"
)

# Execute the business use case
service.schedule_new_session(new_session)
print(f"Session {new_session.id} successfully saved to the Repository.")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>architecture</category>
      <category>backend</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Mastering Design Principles: Dependency Inversion in Kotlin</title>
      <dc:creator>Renzo Fernando LOYOLA VILCA CHOQUE</dc:creator>
      <pubDate>Wed, 17 Jun 2026 23:35:24 +0000</pubDate>
      <link>https://dev.to/renzo_fernandoloyolavil/mastering-design-principles-dependency-inversion-in-kotlin-4mp8</link>
      <guid>https://dev.to/renzo_fernandoloyolavil/mastering-design-principles-dependency-inversion-in-kotlin-4mp8</guid>
      <description>&lt;p&gt;Abstract&lt;/p&gt;

&lt;p&gt;In modern software engineering, writing code that simply "works" is only the first step. The real challenge lies in designing systems that are maintainable, scalable, and easy to test. This article explores the Dependency Inversion Principle (DIP), the final pillar of the SOLID design principles. Through a practical, real-world example in Kotlin, we will demonstrate how to transition from a tightly coupled architecture to an abstraction-based design. This shift dramatically improves our codebase, facilitates unit testing, and prepares our applications for future growth.&lt;/p&gt;

&lt;p&gt;Introduction: The Chaos of Coupling&lt;/p&gt;

&lt;p&gt;As applications grow, it is common to see how a minor change in a database schema or a third-party API triggers a domino effect, breaking unrelated parts of the system. This fragility is a direct consequence of tight coupling.&lt;/p&gt;

&lt;p&gt;Software design principles, particularly SOLID, were established to prevent this architectural decay. Today, we focus on the "D" in SOLID: the Dependency Inversion Principle (DIP). This principle establishes two core rules:&lt;/p&gt;

&lt;p&gt;High-level modules should not depend on low-level modules. Both should depend on abstractions (interfaces).&lt;/p&gt;

&lt;p&gt;Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.&lt;/p&gt;

&lt;p&gt;The Scenario: An E-commerce Payment Processor&lt;/p&gt;

&lt;p&gt;Imagine you are building the billing system for an online store. To process purchases, the system needs to connect to a payment gateway, such as PayPal.&lt;/p&gt;

&lt;p&gt;The Bad Way: Tight Coupling (Violating DIP)&lt;/p&gt;

&lt;p&gt;In this initial design, our high-level business logic (OrderProcessor) directly instantiates and depends on the concrete low-level class (PayPalService).&lt;/p&gt;

&lt;p&gt;// Low-level component (Concrete detail)&lt;br&gt;
class PayPalService {&lt;br&gt;
    fun executePayment(amount: Double) {&lt;br&gt;
        println("Processing payment of $$amount via PayPal API.")&lt;br&gt;
    }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// High-level component (Business logic)&lt;br&gt;
class OrderProcessor {&lt;br&gt;
    // Tight coupling: this class depends directly on a concrete implementation&lt;br&gt;
    private val payPalService = PayPalService() &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun completeOrder(orderId: String, total: Double) {
    println("Initiating processing for order: $orderId")
    payPalService.executePayment(total)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;fun main() {&lt;br&gt;
    val processor = OrderProcessor()&lt;br&gt;
    processor.completeOrder("ORD-101", 89.90)&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Why is this design fragile?&lt;/p&gt;

&lt;p&gt;Zero Testability: You cannot easily test OrderProcessor in isolation. Any unit test will attempt to make an actual API call to PayPalService, resulting in slow, brittle tests that depend on network connectivity.&lt;/p&gt;

&lt;p&gt;Rigidity: If the business team decides to switch the payment provider from PayPal to Stripe tomorrow, you will have to manually modify the internal code of OrderProcessor. This also violates the Open/Closed Principle (OCP).&lt;/p&gt;

&lt;p&gt;The Better Way: Introducing Abstraction (Applying DIP)&lt;/p&gt;

&lt;p&gt;To resolve this, we invert the dependency. We introduce an interface that acts as a contract between the high-level business logic and the low-level implementation details. Both components will now depend on this abstraction.&lt;/p&gt;

&lt;p&gt;// 1. Define the Abstraction (The contract)&lt;br&gt;
interface PaymentGateway {&lt;br&gt;
    fun processPayment(amount: Double)&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// 2. Concrete Implementation for PayPal&lt;br&gt;
class PayPalProvider : PaymentGateway {&lt;br&gt;
    override fun processPayment(amount: Double) {&lt;br&gt;
        println("Payment of $$amount processed securely via PayPal.")&lt;br&gt;
    }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// 3. Concrete Implementation for Stripe (Easy to add later!)&lt;br&gt;
class StripeProvider : PaymentGateway {&lt;br&gt;
    override fun processPayment(amount: Double) {&lt;br&gt;
        println("Payment of $$amount processed securely via Stripe.")&lt;br&gt;
    }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// 4. High-level component depending ONLY on the interface&lt;br&gt;
// We use Dependency Injection via the constructor&lt;br&gt;
class OrderProcessor(private val paymentGateway: PaymentGateway) {&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun completeOrder(orderId: String, total: Double) {
    println("Initiating processing for order: $orderId")
    paymentGateway.processPayment(total)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;fun main() {&lt;br&gt;
    // We instantiate the providers independently&lt;br&gt;
    val payPal = PayPalProvider()&lt;br&gt;
    val stripe = StripeProvider()&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Now we inject whichever dependency we need at runtime
println("--- Using PayPal ---")
val orderProcessorWithPayPal = OrderProcessor(payPal)
orderProcessorWithPayPal.completeOrder("ORD-202", 45.00)

println("\n--- Using Stripe ---")
val orderProcessorWithStripe = OrderProcessor(stripe)
orderProcessorWithStripe.completeOrder("ORD-203", 120.50)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;Conclusion&lt;/p&gt;

&lt;p&gt;By applying the Dependency Inversion Principle, we transformed a rigid, high-maintenance codebase into a highly modular, decoupled system.&lt;/p&gt;

&lt;p&gt;Key Benefits:&lt;/p&gt;

&lt;p&gt;Maintainability: Adding a new payment gateway (e.g., Apple Pay or Google Pay) does not require changing a single line of code in the OrderProcessor. We simply create a new class implementing the PaymentGateway interface.&lt;/p&gt;

&lt;p&gt;Excellent Testability: In a unit testing environment, you can pass a mocked implementation of PaymentGateway to OrderProcessor, verifying its business logic without invoking real network requests or external APIs.&lt;/p&gt;

&lt;p&gt;Investing time in establishing clean boundaries between components pays off immensely as your codebase scales. Clean code is happy code!&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>kotlin</category>
      <category>softwareengineering</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Draft Article: Mastering Software Design Principles</title>
      <dc:creator>Renzo Fernando LOYOLA VILCA CHOQUE</dc:creator>
      <pubDate>Wed, 17 Jun 2026 23:25:47 +0000</pubDate>
      <link>https://dev.to/renzo_fernandoloyolavil/draft-article-mastering-software-design-principles-38k4</link>
      <guid>https://dev.to/renzo_fernandoloyolavil/draft-article-mastering-software-design-principles-38k4</guid>
      <description>&lt;p&gt;Beyond Spaghetti Code: Embracing the Dependency Inversion Principle in Kotlin&lt;br&gt;
Abstract&lt;br&gt;
In modern software engineering, writing code that "just works" is no longer enough. The real challenge lies in designing systems that are maintainable, scalable, and resilient to change. This article explores the core concepts of Software Design Principles, focusing on the Dependency Inversion Principle (DIP) from SOLID. Through a practical, real-world example in Kotlin, we will demonstrate how moving from tightly coupled implementations to clean abstractions can dramatically improve your codebase's testability and flexibility.&lt;/p&gt;

&lt;p&gt;Introduction: Why Design Principles Matter&lt;br&gt;
As applications grow, codebases tend to become rigid. A simple change in a database structure or a third-party API can trigger a domino effect of bugs across the entire system. This is where software design principles come to the rescue.&lt;/p&gt;

&lt;p&gt;By adhering to established architectural patterns and principles (such as SOLID, DRY, and KISS), developers can decouple components. This ensures that modules can be modified, replaced, or tested independently without breaking the surrounding infrastructure.&lt;/p&gt;

&lt;p&gt;The Real-World Scenario: A Payment Gateway Integration&lt;br&gt;
Imagine you are building an e-commerce application. One of the core requirements is processing payments. A naive approach often results in a high-level module (like an order processor) directly depending on a low-level concrete implementation (like a specific payment provider's SDK).&lt;/p&gt;

&lt;p&gt;The Bad Way: Tight Coupling (Violating DIP)&lt;br&gt;
In the code snippet below, our OrderProcessor is completely tied to a specific PayPalService. If marketing decides to switch to Stripe tomorrow, or if we want to run unit tests without hitting the real live API, we are in deep trouble.&lt;/p&gt;

&lt;p&gt;// Low-level concrete component&lt;br&gt;
class PayPalService {&lt;br&gt;
    fun executePayment(amount: Double) {&lt;br&gt;
        println("Processing payment of $$amount via PayPal API.")&lt;br&gt;
    }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// High-level component directly depending on a concrete class&lt;br&gt;
class OrderProcessor {&lt;br&gt;
    private val payPalService = PayPalService() // Tight coupling!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun completeOrder(orderId: String, total: Double) {
    println("Completing order: $orderId")
    payPalService.executePayment(total)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;fun main() {&lt;br&gt;
    val processor = OrderProcessor()&lt;br&gt;
    processor.completeOrder("ORD-1001", 79.99)&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Why this is fragile:&lt;/p&gt;

&lt;p&gt;Zero Testability: You cannot easily mock PayPalService to test OrderProcessor logic in isolation.&lt;/p&gt;

&lt;p&gt;Rigidity: Changing the payment provider requires rewrites inside OrderProcessor.&lt;/p&gt;

&lt;p&gt;The Better Way: Introducing Abstraction (Applying DIP)&lt;br&gt;
To fix this, the Dependency Inversion Principle dictates that high-level modules should not depend on low-level modules; both should depend on abstractions.&lt;/p&gt;

&lt;p&gt;Let's refactor the code by introducing a PaymentService interface.&lt;/p&gt;

&lt;p&gt;// The Abstraction layer&lt;br&gt;
interface PaymentService {&lt;br&gt;
    fun processPayment(amount: Double)&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// Low-level concrete implementation 1&lt;br&gt;
class PayPalProvider : PaymentService {&lt;br&gt;
    override fun processPayment(amount: Double) {&lt;br&gt;
        println("Securely processing $$amount via PayPal.")&lt;br&gt;
    }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// Low-level concrete implementation 2 (Easy to add later!)&lt;br&gt;
class StripeProvider : PaymentService {&lt;br&gt;
    override fun processPayment(amount: Double) {&lt;br&gt;
        println("Securely processing $$amount via Stripe.")&lt;br&gt;
    }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// High-level component depending ONLY on the interface&lt;br&gt;
class OrderProcessor(private val paymentService: PaymentService) { // Dependency Injection&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun completeOrder(orderId: String, total: Double) {
    println("Completing order: $orderId")
    paymentService.processPayment(total)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;fun main() {&lt;br&gt;
    // We can swap the provider effortlessly via construction&lt;br&gt;
    val payPalProvider = PayPalProvider()&lt;br&gt;
    val stripeProvider = StripeProvider()&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val orderProcessorWithPayPal = OrderProcessor(payPalProvider)
orderProcessorWithPayPal.completeOrder("ORD-2002", 45.50)

val orderProcessorWithStripe = OrderProcessor(stripeProvider)
orderProcessorWithStripe.completeOrder("ORD-2003", 120.00)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;Conclusion&lt;br&gt;
By inverting dependencies using Kotlin's clean interface and constructor injection capabilities, we transformed a rigid, untestable class into a highly adaptable component. Now, adding new payment providers or injecting fake mock instances for unit testing requires zero changes to the underlying business logic of OrderProcessor.&lt;/p&gt;

&lt;p&gt;Investing time in robust software design principles early in development saves countless hours of refactoring down the road. Happy coding!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Secure Your Python App Using Bandit as a SAST Tool</title>
      <dc:creator>Renzo Fernando LOYOLA VILCA CHOQUE</dc:creator>
      <pubDate>Sat, 06 Dec 2025 01:18:08 +0000</pubDate>
      <link>https://dev.to/renzo_fernandoloyolavil/secure-your-python-app-using-bandit-as-a-sast-tool-1ofm</link>
      <guid>https://dev.to/renzo_fernandoloyolavil/secure-your-python-app-using-bandit-as-a-sast-tool-1ofm</guid>
      <description>&lt;p&gt;Static Application Security Testing (SAST) tools help you detect vulnerabilities directly in your source code before the application is executed or deployed. In this article, you will see how to use Bandit, a Python‑focused SAST tool, to scan a Python application and improve its security posture.​&lt;/p&gt;

&lt;p&gt;What Is SAST and Why It Matters&lt;br&gt;
SAST refers to techniques and tools that analyze source code, bytecode or binaries to find security weaknesses without running the application. These tools search for patterns related to insecure practices such as injection, unsafe system calls, weak cryptography, or hardcoded secrets.​&lt;/p&gt;

&lt;p&gt;Running SAST early in the development lifecycle allows teams to detect and fix issues before they reach production, which reduces both risk and remediation cost. Integrating SAST into everyday workflows (IDE checks, pre‑commit hooks or CI/CD pipelines) transforms security from a late, manual step into a continuous, automated practice.​&lt;/p&gt;

&lt;p&gt;Meet Bandit: A Python Security Linter&lt;br&gt;
Bandit is an open source security linter designed to find common security issues in Python code. It parses Python files, builds an abstract syntax tree (AST), and runs a set of security tests to detect problems such as hardcoded passwords, use of unsafe functions like exec, insecure random generators, weak hashes, or risky XML and subprocess usage.​&lt;/p&gt;

&lt;p&gt;Because Bandit understands Python syntax and idioms, it can provide more precise findings than generic text‑based scanners for this language. It is distributed through PyPI, actively maintained by the PyCQA community, and can be easily integrated into local development workflows and CI/CD pipelines.​&lt;/p&gt;

&lt;p&gt;Setting Up Bandit in Your Project&lt;br&gt;
To use Bandit, you only need a working Python environment and pip. Many developers prefer to create a virtual environment so that security tools and project dependencies do not conflict.​&lt;/p&gt;

&lt;p&gt;Example setup steps (run in your terminal):&lt;/p&gt;

&lt;p&gt;Create and activate a virtual environment (optional).​&lt;/p&gt;

&lt;p&gt;Install Bandit with pip: pip install bandit.​&lt;/p&gt;

&lt;p&gt;Optionally, install extra features like TOML support, baseline management or SARIF output using extras such as bandit[toml], bandit[baseline] or bandit[sarif].​&lt;/p&gt;

&lt;p&gt;After installation, the bandit command becomes available in your shell so you can run it from any project directory.​&lt;/p&gt;

&lt;p&gt;Scanning a Python Application with Bandit&lt;br&gt;
Once Bandit is installed, you can scan either a single file or an entire project directory. The most common workflow is to navigate to the root of your Python project and run Bandit recursively.​&lt;/p&gt;

&lt;p&gt;Typical examples:&lt;/p&gt;

&lt;p&gt;Scan a single file: bandit app.py&lt;/p&gt;

&lt;p&gt;Scan a whole project recursively: bandit -r .&lt;/p&gt;

&lt;p&gt;When the scan finishes, Bandit prints a report showing each issue it found, along with fields like severity, confidence, file path, line number and a short description. You can also change the output format to JSON, XML, HTML, YAML and others, which is useful for storing results or integrating with dashboards.​&lt;/p&gt;

&lt;p&gt;Understanding Bandit’s Output&lt;br&gt;
Bandit assigns two key attributes to each finding: severity and confidence. Severity indicates how serious the potential vulnerability is (for example low, medium or high), while confidence reflects how certain Bandit is that the pattern represents a real security problem.​&lt;/p&gt;

&lt;p&gt;High‑severity, high‑confidence issues typically indicate dangerous patterns such as use of weak cryptographic functions, insecure temporary files, unsafe XML parsers or shell commands with untrusted input. Developers should review these findings in context, confirm whether they are valid issues, and then apply fixes such as input validation, parameterization, replacing weak algorithms or refactoring dangerous code.​&lt;/p&gt;

&lt;p&gt;Applying Bandit to a Sample Scenario&lt;br&gt;
Imagine a small Python web application that performs file operations, calls external commands and processes user input. Bandit can help identify if:&lt;/p&gt;

&lt;p&gt;Temporary files are created using insecure methods.​&lt;/p&gt;

&lt;p&gt;User input is passed directly into shell commands or SQL queries.​&lt;/p&gt;

&lt;p&gt;Insecure modules like telnetlib or weak hash functions like md5 are in use.​&lt;/p&gt;

&lt;p&gt;Running bandit -r . from the project root will reveal these patterns with line numbers and explanations, making it easier to refactor the application before deployment.​&lt;/p&gt;

&lt;p&gt;Integrating Bandit into CI/CD&lt;br&gt;
The real power of a SAST tool appears when it becomes part of your automated pipelines. With Bandit, you can add a CI job that installs dependencies, runs bandit -r ., and fails the pipeline if new high‑severity issues are introduced.​&lt;/p&gt;

&lt;p&gt;For example, in a GitHub Actions or GitLab CI pipeline, you can:&lt;/p&gt;

&lt;p&gt;Use a Python base image, install Bandit and run it as part of your test stage.​&lt;/p&gt;

&lt;p&gt;Configure Bandit to output JSON or SARIF and upload that report as a pipeline artifact or feed it into security dashboards.​&lt;/p&gt;

&lt;p&gt;Optionally, use a baseline file to compare current results against previous scans, so only new findings break the build.​&lt;/p&gt;

&lt;p&gt;This approach ensures every pull request is checked for security issues, not only for functionality or style.​&lt;/p&gt;

&lt;p&gt;Best Practices When Using Bandit&lt;br&gt;
To get the most value from Bandit, consider these practices:&lt;/p&gt;

&lt;p&gt;Run Bandit locally as part of a pre‑commit hook so that insecure patterns are caught before code is pushed.​&lt;/p&gt;

&lt;p&gt;Adjust severity and confidence thresholds to match your project’s risk tolerance, focusing on high‑impact issues first.​&lt;/p&gt;

&lt;p&gt;Regularly review and update the configuration (for example .bandit.yml) to skip false positives or define project‑specific rules.​&lt;/p&gt;

&lt;p&gt;Combine Bandit with other security practices such as dependency scanning, dynamic testing and manual code review.​&lt;/p&gt;

&lt;p&gt;Bandit is not a silver bullet, but it is a lightweight and effective way to bring security awareness into everyday Python development.​&lt;/p&gt;

&lt;p&gt;Limitations and Complementary Tools&lt;br&gt;
Bandit focuses on static analysis of Python source code, so it does not replace dynamic application security testing or runtime protection. It may also miss complex logic issues that require deeper understanding of business rules, which is why human review remains essential.​&lt;/p&gt;

&lt;p&gt;For a more complete security strategy, combine Bandit with tools that check open‑source dependencies, perform dynamic scans against running environments and monitor production systems. Even with these limitations, integrating Bandit as your SAST tool for Python significantly raises your application’s security baseline with relatively low effort&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Applying API testing frameworks: real-world code examples</title>
      <dc:creator>Renzo Fernando LOYOLA VILCA CHOQUE</dc:creator>
      <pubDate>Sat, 06 Dec 2025 00:53:35 +0000</pubDate>
      <link>https://dev.to/renzo_fernandoloyolavil/applying-api-testing-frameworks-real-world-code-examples-424n</link>
      <guid>https://dev.to/renzo_fernandoloyolavil/applying-api-testing-frameworks-real-world-code-examples-424n</guid>
      <description>&lt;p&gt;Applying API testing frameworks: real-world code examples&lt;br&gt;
Modern applications dependen de APIs para conectar frontends, servicios internos y terceros. Validar estas APIs de forma automática es clave para evitar regresiones y detectar errores antes de llegar a producción. En este artículo verás cómo aplicar marcos de prueba de API con ejemplos reales usando Postman (JavaScript) y Rest Assured (Java), y cómo integrarlos en un flujo de CI/CD.​&lt;/p&gt;

&lt;p&gt;Why API testing matters&lt;br&gt;
API testing permite validar lógica de negocio, contratos y reglas de seguridad sin necesidad de una interfaz gráfica. Cuando se integra en pipelines de CI/CD, ayuda a detectar fallos de manera temprana y a mantener lanzamientos frecuentes pero estables. Además, automatizar estas pruebas reduce el trabajo manual del QA y mejora la confianza en cada despliegue.​&lt;/p&gt;

&lt;p&gt;Choosing an API testing framework&lt;br&gt;
Existen múltiples herramientas para probar APIs: Postman, Rest Assured, Karate, JMeter, SoapUI, entre otras. Cada una ofrece ventajas según el lenguaje, el tipo de proyecto y el nivel de experiencia del equipo. En este artículo nos centraremos en dos opciones muy usadas en la industria: Postman para flujos rápidos y colaborativos, y Rest Assured para pruebas integradas en suites Java.​&lt;/p&gt;

&lt;p&gt;Postman: testing with JavaScript&lt;br&gt;
Postman es una herramienta muy popular para diseñar, documentar y probar APIs, tanto de forma manual como automatizada. Permite agrupar peticiones en Collections, usar entornos con variables, y añadir scripts en JavaScript para ejecutar aserciones sobre las respuestas.​&lt;/p&gt;

&lt;p&gt;Un flujo típico de prueba funcional en Postman incluye:&lt;/p&gt;

&lt;p&gt;Definir la petición (método, URL, headers, body).&lt;/p&gt;

&lt;p&gt;Añadir scripts en la pestaña “Tests” para validar el resultado.&lt;/p&gt;

&lt;p&gt;Ejecutar la Collection de manera local o en un pipeline CI/CD.&lt;/p&gt;

&lt;p&gt;Real-world example: validating a GET endpoint in Postman&lt;br&gt;
Supongamos una API de librería con el endpoint GET /books/{id} que devuelve los detalles de un libro. El objetivo de la prueba es validar que el servicio responde con código 200 y que el cuerpo incluye campos como id, title y author con datos válidos.​&lt;/p&gt;

&lt;p&gt;En Postman, la prueba podría incluir aserciones como:&lt;/p&gt;

&lt;p&gt;js&lt;br&gt;
pm.test("Status code is 200", function () {&lt;br&gt;
    pm.response.to.have.status(200);&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;pm.test("Response body has required fields", function () {&lt;br&gt;
    const json = pm.response.json();&lt;br&gt;
    pm.expect(json).to.have.property("id");&lt;br&gt;
    pm.expect(json).to.have.property("title");&lt;br&gt;
    pm.expect(json).to.have.property("author");&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;pm.test("Book id matches requested id", function () {&lt;br&gt;
    const json = pm.response.json();&lt;br&gt;
    const requestedId = pm.request.url.variables.get("id");&lt;br&gt;
    pm.expect(json.id.toString()).to.eql(requestedId);&lt;br&gt;
});&lt;br&gt;
Este tipo de script se ejecuta automáticamente después de cada llamada y te permite validar tanto el código de estado como la estructura del JSON.​&lt;/p&gt;

&lt;p&gt;Data-driven tests with Postman&lt;br&gt;
En escenarios reales, es habitual probar el mismo endpoint con distintos datos de entrada. Postman soporta pruebas orientadas a datos usando archivos CSV o JSON, donde cada fila representa un conjunto de variables para la ejecución.​&lt;/p&gt;

&lt;p&gt;Por ejemplo, un archivo CSV podría contener varios bookId y valores esperados, y la Collection Runner los iterará de manera automática. Esto permite cubrir casos positivos y negativos (IDs válidos, inexistentes o inválidos) sin duplicar manualmente las peticiones.​&lt;/p&gt;

&lt;p&gt;Rest Assured: Java-based API testing&lt;br&gt;
Rest Assured es un framework para pruebas de API en Java que simplifica el envío de peticiones HTTP y la validación de respuestas. Se integra bien con TestNG o JUnit, lo que facilita su uso dentro de suites automatizadas y pipelines de CI/CD.​&lt;/p&gt;

&lt;p&gt;Su enfoque fluido permite escribir pruebas legibles, y combinarlo con librerías como Hamcrest para aserciones expresivas sobre JSON y XML. Además, soporta múltiples métodos HTTP, autenticación, parámetros, logs y manejo de serialización/deserialización.​&lt;/p&gt;

&lt;p&gt;Real-world example: Rest Assured GET test&lt;br&gt;
Tomando el mismo escenario de GET /books/{id}, una prueba en Rest Assured podría validar el status code y campos clave de la respuesta JSON.​&lt;/p&gt;

&lt;p&gt;java&lt;br&gt;
import static io.restassured.RestAssured.&lt;em&gt;;&lt;br&gt;
import static org.hamcrest.Matchers.&lt;/em&gt;;&lt;br&gt;
import org.testng.annotations.Test;&lt;/p&gt;

&lt;p&gt;public class BookApiTest {&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Test
public void getBookById_shouldReturnValidBook() {
    given()
        .baseUri("https://api.example.com")
        .basePath("/books/{id}")
        .pathParam("id", 1)
    .when()
        .get()
    .then()
        .statusCode(200)
        .body("id", equalTo(1))
        .body("title", notNullValue())
        .body("author", notNullValue());
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
Este tipo de prueba se puede ejecutar junto con el resto del suite de tests de backend, formando parte del proceso de build.​&lt;/p&gt;

&lt;p&gt;Creating reusable components in Rest Assured&lt;br&gt;
En casos reales, resulta útil extraer configuraciones repetidas como baseUri, headers comunes o autenticación a una clase base. De esta forma, las pruebas se enfocan en el comportamiento, no en el detalle de configuración de cada endpoint.​&lt;/p&gt;

&lt;p&gt;Por ejemplo, se puede definir una clase BaseApiTest que configure Rest Assured en un método @BeforeClass y luego extenderla desde las clases que representan cada módulo de la API (books, users, orders, etc.).​&lt;/p&gt;

&lt;p&gt;Testing authenticated APIs&lt;br&gt;
Muchos servicios exponen endpoints protegidos mediante API keys, tokens Bearer u OAuth2. Tanto Postman como Rest Assured ofrecen soporte para este tipo de autenticación, ya sea configurando headers, usando helpers integrados o generando tokens previos a las pruebas.​&lt;/p&gt;

&lt;p&gt;En Rest Assured, por ejemplo, se puede añadir un header de autorización de forma global o en cada prueba:&lt;/p&gt;

&lt;p&gt;java&lt;br&gt;
given()&lt;br&gt;
    .baseUri("&lt;a href="https://api.example.com%22" rel="noopener noreferrer"&gt;https://api.example.com"&lt;/a&gt;)&lt;br&gt;
    .header("Authorization", "Bearer " + token)&lt;br&gt;
    .when()&lt;br&gt;
    .get("/books")&lt;br&gt;
    .then()&lt;br&gt;
    .statusCode(200);&lt;br&gt;
En Postman, puedes almacenar el token en una variable de entorno y referenciarlo en el header Authorization mediante {{token}}.​&lt;/p&gt;

&lt;p&gt;Integrating API tests into CI/CD&lt;br&gt;
El verdadero valor de estos marcos se ve cuando se integran en pipelines de CI/CD como GitHub Actions, Jenkins o GitLab CI. La idea es ejecutar suites de pruebas de API en cada push o antes de un despliegue para evitar que cambios en el código rompan contratos existentes.​&lt;/p&gt;

&lt;p&gt;Algunos enfoques habituales son:&lt;/p&gt;

&lt;p&gt;Ejecutar Collections de Postman mediante Newman en un job del pipeline.&lt;/p&gt;

&lt;p&gt;Ejecutar tests de Rest Assured con Maven/Gradle como parte del stage de test.&lt;/p&gt;

&lt;p&gt;Publicar reportes (HTML, JUnit) como artefactos del pipeline para su revisión.&lt;/p&gt;

&lt;p&gt;Example: running Postman tests in CI&lt;br&gt;
Newman, el CLI de Postman, permite ejecutar collections dentro de un flujo automatizado. Un paso típico en un pipeline podría incluir un comando como:​&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
newman run LibraryAPI.postman_collection.json \&lt;br&gt;
  -e staging.postman_environment.json \&lt;br&gt;
  --reporters cli,junit \&lt;br&gt;
  --reporter-junit-export newman-report.xml&lt;br&gt;
Ese reporte puede ser consumido por la plataforma de CI/CD para marcar el build como exitoso o fallido según los resultados de las pruebas.​&lt;/p&gt;

&lt;p&gt;Example: running Rest Assured in CI&lt;br&gt;
Para proyectos Java, lo más habitual es ejecutar los tests de Rest Assured junto con el resto de pruebas unitarias e integradas. En un pipeline que use Maven, bastaría con un job que ejecute mvn test y recoja los informes generados.​&lt;/p&gt;

&lt;p&gt;Combinado con herramientas de reporte como surefire-report o plugins de informes HTML, es posible ver en detalle qué endpoints fallaron, qué payload se envió y cuál fue la respuesta recibida.​&lt;/p&gt;

&lt;p&gt;Putting it all together&lt;br&gt;
Aplicar marcos de prueba de API en proyectos reales significa ir más allá de pruebas manuales puntuales y construir suites automatizadas que vivan junto al código. Usando Postman puedes cubrir rápidamente escenarios funcionales y colaborativos, mientras que Rest Assured te permite integrar pruebas de API directamente en tu base de código Java y pipeline de CI/CD.​&lt;/p&gt;

&lt;p&gt;Al combinar ambos enfoques, obtienes una cobertura robusta: validaciones funcionales, pruebas con datos, escenarios autenticados y ejecución continua en cada cambio. Esto se traduce en APIs más confiables, menos incidentes en producción y un ciclo de desarrollo más seguro y predecible&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Securing Infrastructure as Code with Checkov: A Practical SAST Approach</title>
      <dc:creator>Renzo Fernando LOYOLA VILCA CHOQUE</dc:creator>
      <pubDate>Sat, 06 Dec 2025 00:41:48 +0000</pubDate>
      <link>https://dev.to/renzo_fernandoloyolavil/securing-infrastructure-as-code-with-checkov-a-practical-sast-approach-58co</link>
      <guid>https://dev.to/renzo_fernandoloyolavil/securing-infrastructure-as-code-with-checkov-a-practical-sast-approach-58co</guid>
      <description>&lt;p&gt;Introduction&lt;br&gt;
Infrastructure as Code (IaC) has revolutionized how we manage and deploy cloud resources. However, with great power comes great responsibility. Security misconfigurations in IaC templates can lead to serious vulnerabilities in production environments. This is where Static Application Security Testing (SAST) tools like Checkov come into play.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore how to implement Checkov, a powerful open-source SAST tool, to scan and secure your Infrastructure as Code across multiple platforms including Terraform, CloudFormation, Kubernetes, and more.&lt;/p&gt;

&lt;p&gt;What is Checkov?&lt;br&gt;
Checkov is a static code analysis tool developed by Bridgecrew (now part of Palo Alto Networks) that scans infrastructure code for security and compliance misconfigurations. It supports:&lt;/p&gt;

&lt;p&gt;Terraform&lt;br&gt;
CloudFormation&lt;br&gt;
Kubernetes&lt;br&gt;
Helm&lt;br&gt;
ARM Templates&lt;br&gt;
Serverless Framework&lt;br&gt;
Docker&lt;br&gt;
And many more...&lt;br&gt;
Why Use SAST for Infrastructure as Code?&lt;br&gt;
Early Detection: Identify security issues before they reach production&lt;br&gt;
Compliance: Ensure adherence to industry standards (CIS, PCI-DSS, HIPAA)&lt;br&gt;
Cost Reduction: Fix issues early in the development cycle&lt;br&gt;
Automation: Integrate seamlessly into CI/CD pipelines&lt;br&gt;
Policy as Code: Define and enforce organizational security policies&lt;/p&gt;

&lt;p&gt;Getting Started with Checkov&lt;br&gt;
Installation&lt;br&gt;
Checkov can be installed using pip:&lt;/p&gt;

&lt;p&gt;pip install checkov&lt;br&gt;
Or using Docker:&lt;/p&gt;

&lt;p&gt;docker pull bridgecrew/checkov&lt;br&gt;
Basic Usage&lt;br&gt;
Scan a Terraform directory:&lt;/p&gt;

&lt;p&gt;checkov -d /path/to/terraform&lt;br&gt;
Scan a specific file:&lt;/p&gt;

&lt;p&gt;checkov -f main.tf&lt;br&gt;
Practical Example: Securing Terraform Code&lt;br&gt;
Let's examine a vulnerable Terraform configuration and how Checkov identifies the issues.&lt;/p&gt;

&lt;p&gt;Vulnerable Configuration&lt;/p&gt;

&lt;h1&gt;
  
  
  main.tf - INSECURE EXAMPLE
&lt;/h1&gt;

&lt;p&gt;resource "aws_s3_bucket" "data_bucket" {&lt;br&gt;
  bucket = "my-data-bucket"&lt;/p&gt;

&lt;p&gt;# Missing encryption&lt;br&gt;
  # Missing versioning&lt;br&gt;
  # Missing logging&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;resource "aws_security_group" "web_sg" {&lt;br&gt;
  name        = "web-security-group"&lt;br&gt;
  description = "Security group for web servers"&lt;/p&gt;

&lt;p&gt;ingress {&lt;br&gt;
    from_port   = 0&lt;br&gt;
    to_port     = 0&lt;br&gt;
    protocol    = "-1"&lt;br&gt;
    cidr_blocks = ["0.0.0.0/0"]  # Too permissive!&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;resource "aws_db_instance" "database" {&lt;br&gt;
  allocated_storage    = 20&lt;br&gt;
  engine              = "mysql"&lt;br&gt;
  instance_class      = "db.t3.micro"&lt;br&gt;
  username            = "admin"&lt;br&gt;
  password            = "hardcodedpassword123"  # Hardcoded password!&lt;br&gt;
  skip_final_snapshot = true&lt;/p&gt;

&lt;p&gt;# Missing encryption&lt;br&gt;
  # Publicly accessible by default&lt;br&gt;
}&lt;br&gt;
Running Checkov&lt;br&gt;
checkov -f main.tf --output json --output-file results.json&lt;br&gt;
Checkov Output&lt;br&gt;
Checkov will identify multiple security issues:&lt;/p&gt;

&lt;p&gt;Check: CKV_AWS_18: "Ensure the S3 bucket has access logging enabled"&lt;br&gt;
Check: CKV_AWS_19: "Ensure the S3 bucket has server-side encryption enabled"&lt;br&gt;
Check: CKV_AWS_21: "Ensure the S3 bucket has versioning enabled"&lt;br&gt;
Check: CKV_AWS_23: "Ensure Security Group does not allow ingress from 0.0.0.0/0 to port 22"&lt;br&gt;
Check: CKV_AWS_16: "Ensure RDS database is encrypted at rest"&lt;br&gt;
Check: CKV_AWS_41: "Ensure RDS instance has IAM authentication enabled"&lt;br&gt;
Secure Configuration&lt;br&gt;
Now let's fix these issues:&lt;/p&gt;

&lt;h1&gt;
  
  
  main.tf - SECURE VERSION
&lt;/h1&gt;

&lt;p&gt;resource "aws_s3_bucket" "data_bucket" {&lt;br&gt;
  bucket = "my-data-bucket"&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;resource "aws_s3_bucket_versioning" "data_bucket_versioning" {&lt;br&gt;
  bucket = aws_s3_bucket.data_bucket.id&lt;br&gt;
  versioning_configuration {&lt;br&gt;
    status = "Enabled"&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;resource "aws_s3_bucket_server_side_encryption_configuration" "data_bucket_encryption" {&lt;br&gt;
  bucket = aws_s3_bucket.data_bucket.id&lt;/p&gt;

&lt;p&gt;rule {&lt;br&gt;
    apply_server_side_encryption_by_default {&lt;br&gt;
      sse_algorithm = "AES256"&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;resource "aws_s3_bucket_logging" "data_bucket_logging" {&lt;br&gt;
  bucket = aws_s3_bucket.data_bucket.id&lt;/p&gt;

&lt;p&gt;target_bucket = aws_s3_bucket.log_bucket.id&lt;br&gt;
  target_prefix = "log/"&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;resource "aws_security_group" "web_sg" {&lt;br&gt;
  name        = "web-security-group"&lt;br&gt;
  description = "Security group for web servers"&lt;/p&gt;

&lt;p&gt;ingress {&lt;br&gt;
    from_port   = 443&lt;br&gt;
    to_port     = 443&lt;br&gt;
    protocol    = "tcp"&lt;br&gt;
    cidr_blocks = ["10.0.0.0/8"]  # Restricted to internal network&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;egress {&lt;br&gt;
    from_port   = 0&lt;br&gt;
    to_port     = 0&lt;br&gt;
    protocol    = "-1"&lt;br&gt;
    cidr_blocks = ["0.0.0.0/0"]&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;resource "aws_db_instance" "database" {&lt;br&gt;
  allocated_storage    = 20&lt;br&gt;
  engine              = "mysql"&lt;br&gt;
  instance_class      = "db.t3.micro"&lt;br&gt;
  username            = "admin"&lt;br&gt;
  password            = var.db_password  # Using variable instead&lt;br&gt;
  skip_final_snapshot = false&lt;/p&gt;

&lt;p&gt;storage_encrypted          = true&lt;br&gt;
  iam_database_authentication_enabled = true&lt;br&gt;
  publicly_accessible        = false&lt;/p&gt;

&lt;p&gt;backup_retention_period = 7&lt;br&gt;
  enabled_cloudwatch_logs_exports = ["error", "general", "slowquery"]&lt;br&gt;
}&lt;br&gt;
Integrating Checkov into CI/CD&lt;br&gt;
GitHub Actions Example&lt;br&gt;
name: IaC Security Scan&lt;/p&gt;

&lt;p&gt;on: [push, pull_request]&lt;/p&gt;

&lt;p&gt;jobs:&lt;br&gt;
  checkov:&lt;br&gt;
    runs-on: ubuntu-latest&lt;br&gt;
    steps:&lt;br&gt;
      - name: Checkout code&lt;br&gt;
        uses: actions/checkout@v3&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  - name: Set up Python
    uses: actions/setup-python@v4
    with:
      python-version: '3.9'

  - name: Install Checkov
    run: pip install checkov

  - name: Run Checkov
    run: |
      checkov -d . --output cli --output json --output-file checkov-report.json

  - name: Upload results
    uses: actions/upload-artifact@v3
    if: always()
    with:
      name: checkov-report
      path: checkov-report.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;GitLab CI Example&lt;br&gt;
checkov:&lt;br&gt;
  stage: test&lt;br&gt;
  image: bridgecrew/checkov:latest&lt;br&gt;
  script:&lt;br&gt;
    - checkov -d . --output cli --output junitxml --output-file checkov-report.xml&lt;br&gt;
  artifacts:&lt;br&gt;
    reports:&lt;br&gt;
      junit: checkov-report.xml&lt;br&gt;
Custom Policies&lt;br&gt;
Checkov allows you to create custom policies using Python:&lt;/p&gt;

&lt;p&gt;from checkov.common.models.enums import CheckResult, CheckCategories&lt;br&gt;
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck&lt;/p&gt;

&lt;p&gt;class S3BucketEncryption(BaseResourceCheck):&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self):&lt;br&gt;
        name = "Ensure S3 bucket is encrypted with KMS"&lt;br&gt;
        id = "CKV_AWS_CUSTOM_1"&lt;br&gt;
        supported_resources = ['aws_s3_bucket']&lt;br&gt;
        categories = [CheckCategories.ENCRYPTION]&lt;br&gt;
        super().&lt;strong&gt;init&lt;/strong&gt;(name=name, id=id, categories=categories, &lt;br&gt;
                         supported_resources=supported_resources)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def scan_resource_conf(self, conf):
    if 'server_side_encryption_configuration' in conf:
        encryption_config = conf['server_side_encryption_configuration'][0]
        if 'rule' in encryption_config:
            rule = encryption_config['rule'][0]
            if 'apply_server_side_encryption_by_default' in rule:
                encryption = rule['apply_server_side_encryption_by_default'][0]
                if encryption.get('sse_algorithm') == ['aws:kms']:
                    return CheckResult.PASSED
    return CheckResult.FAILED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;check = S3BucketEncryption()&lt;br&gt;
Best Practices&lt;br&gt;
Run Checkov Early: Integrate it into your development workflow&lt;br&gt;
Use Suppressions Wisely: Document why certain checks are suppressed&lt;br&gt;
Keep Checkov Updated: New checks are added regularly&lt;br&gt;
Set Baseline: Use --baseline to track improvements over time&lt;br&gt;
Combine with Other Tools: Use alongside dynamic testing and manual reviews&lt;br&gt;
Educate Your Team: Ensure developers understand the security implications&lt;br&gt;
Suppressing False Positives&lt;br&gt;
Sometimes you need to suppress legitimate findings:&lt;/p&gt;

&lt;p&gt;resource "aws_security_group" "special_case" {&lt;br&gt;
  name = "special-sg"&lt;/p&gt;

&lt;p&gt;#checkov:skip=CKV_AWS_23:This SG is for internal load balancer&lt;br&gt;
  ingress {&lt;br&gt;
    from_port   = 80&lt;br&gt;
    to_port     = 80&lt;br&gt;
    protocol    = "tcp"&lt;br&gt;
    cidr_blocks = ["0.0.0.0/0"]&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
Measuring Success&lt;br&gt;
Track these metrics to measure the effectiveness of Checkov:&lt;/p&gt;

&lt;p&gt;Vulnerability Detection Rate: Number of issues found per scan&lt;br&gt;
Fix Time: Time from detection to remediation&lt;br&gt;
False Positive Rate: Percentage of findings that are not actual issues&lt;br&gt;
Coverage: Percentage of infrastructure code being scanned&lt;br&gt;
Compliance Score: Pass rate against security benchmarks&lt;br&gt;
Conclusion&lt;br&gt;
Implementing SAST tools like Checkov is essential for maintaining secure infrastructure as code. By catching security issues early in the development cycle, you can:&lt;/p&gt;

&lt;p&gt;Reduce security risks in production&lt;br&gt;
Ensure compliance with industry standards&lt;br&gt;
Foster a security-first culture&lt;br&gt;
Save time and money on remediation&lt;br&gt;
Start small by integrating Checkov into one project, measure the results, and gradually expand coverage across your organization. Security is a journey, not a destination, and tools like Checkov are invaluable companions along the way.&lt;/p&gt;

&lt;p&gt;References&lt;br&gt;
Checkov Official Documentation&lt;br&gt;
OWASP Source Code Analysis Tools&lt;br&gt;
Terraform Security Best Practices&lt;br&gt;
CIS Benchmarks&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Dominando las Pruebas de API con Postman: Ejemplos del Mundo Real</title>
      <dc:creator>Renzo Fernando LOYOLA VILCA CHOQUE</dc:creator>
      <pubDate>Thu, 04 Dec 2025 13:04:09 +0000</pubDate>
      <link>https://dev.to/renzo_fernandoloyolavil/dominando-las-pruebas-de-api-con-postman-ejemplos-del-mundo-real-23ld</link>
      <guid>https://dev.to/renzo_fernandoloyolavil/dominando-las-pruebas-de-api-con-postman-ejemplos-del-mundo-real-23ld</guid>
      <description>&lt;h2&gt;
  
  
  Introducción
&lt;/h2&gt;

&lt;p&gt;En el desarrollo de software moderno, las APIs (Interfaces de Programación de Aplicaciones) son la columna vertebral de la comunicación entre sistemas. Postman se ha consolidado como una de las herramientas más populares y poderosas para probar, documentar y automatizar APIs. En este artículo, exploraremos cómo aplicar Postman en escenarios del mundo real, con ejemplos prácticos que puedes implementar inmediatamente.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Por qué Postman?
&lt;/h2&gt;

&lt;p&gt;Postman no es solo un cliente HTTP; es una plataforma completa para el desarrollo de APIs que ofrece:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interfaz intuitiva&lt;/strong&gt;: Ideal para principiantes y expertos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatización de pruebas&lt;/strong&gt;: Scripts JavaScript para validaciones complejas&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Colecciones organizadas&lt;/strong&gt;: Agrupa solicitudes relacionadas&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variables de entorno&lt;/strong&gt;: Facilita el cambio entre dev, staging y producción&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integración CI/CD&lt;/strong&gt;: Compatible con Newman para pipelines automatizados&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Colaboración en equipo&lt;/strong&gt;: Espacios de trabajo compartidos&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Caso de Uso 1: Prueba de API RESTful de E-commerce
&lt;/h2&gt;

&lt;p&gt;Imaginemos que estamos probando una API de una tienda en línea que gestiona productos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Escenario: Obtener lista de productos
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// GET https://api.tienda.com/v1/productos&lt;/span&gt;

&lt;span class="c1"&gt;// En la pestaña "Tests" de Postman:&lt;/span&gt;
&lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;El código de estado es 200&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;La respuesta es JSON&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;La respuesta contiene productos&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jsonData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;an&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;above&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cada producto tiene campos requeridos&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;productos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;productos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;producto&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;producto&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;producto&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nombre&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;producto&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;precio&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;producto&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stock&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Escenario: Crear un nuevo producto (POST)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// POST https://api.tienda.com/v1/productos&lt;/span&gt;
&lt;span class="c1"&gt;// Body (JSON):&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nombre&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Laptop Dell XPS 15&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;precio&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1299.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;categoria&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Electrónica&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stock&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Tests:&lt;/span&gt;
&lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Producto creado exitosamente - 201&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;La respuesta contiene el ID del producto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jsonData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Guardar el ID para usar en solicitudes posteriores&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;producto_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;El precio se guardó correctamente&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jsonData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;precio&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1299.99&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;
  
  
  Caso de Uso 2: Autenticación y Autorización
&lt;/h2&gt;

&lt;p&gt;Las APIs del mundo real requieren autenticación. Veamos cómo manejar tokens JWT.&lt;/p&gt;

&lt;h3&gt;
  
  
  Paso 1: Login y captura de token
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// POST https://api.tienda.com/v1/auth/login&lt;/span&gt;
&lt;span class="c1"&gt;// Body:&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;usuario@ejemplo.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Tests:&lt;/span&gt;
&lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Login exitoso&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Token JWT recibido&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jsonData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Guardar el token en variable de entorno&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jwt_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Guardar timestamp de expiración&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;token_expiry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expiresIn&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;
  
  
  Paso 2: Usar el token en solicitudes protegidas
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// GET https://api.tienda.com/v1/usuario/perfil&lt;/span&gt;
&lt;span class="c1"&gt;// Headers: Authorization: Bearer {{jwt_token}}&lt;/span&gt;

&lt;span class="c1"&gt;// Pre-request Script para verificar token:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jwt_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No hay token de autenticación. Ejecuta primero el login.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Tests:&lt;/span&gt;
&lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Acceso autorizado al perfil&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Datos del usuario son correctos&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usuario&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;usuario&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;usuario&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nombre&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;usuario&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rol&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;Postman es mucho más que una herramienta para enviar solicitudes HTTP. Como hemos visto en estos ejemplos del mundo real:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Validación robusta&lt;/strong&gt;: Podemos verificar códigos de estado, estructura de datos y lógica de negocio&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flujos complejos&lt;/strong&gt;: Encadenamiento de solicitudes con variables dinámicas&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatización&lt;/strong&gt;: Integración perfecta con pipelines CI/CD mediante Newman&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Colaboración&lt;/strong&gt;: Espacios de trabajo compartidos facilitan el trabajo en equipo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentación viva&lt;/strong&gt;: Las colecciones sirven como documentación ejecutable&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Recursos Adicionales
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learning.postman.com/" rel="noopener noreferrer"&gt;Documentación oficial de Postman&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learning.postman.com/docs/getting-started/introduction/" rel="noopener noreferrer"&gt;Postman Learning Center&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman" rel="noopener noreferrer"&gt;Newman en GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Sobre el autor&lt;/strong&gt;: Este artículo forma parte del Trabajo de Investigación N° 02 sobre Comparación de Frameworks de Pruebas de API, desarrollado como parte del curso de Calidad y Pruebas de Software.&lt;/p&gt;

</description>
      <category>api</category>
      <category>testing</category>
      <category>postman</category>
      <category>automation</category>
    </item>
    <item>
      <title>Construyendo un Servidor MCP: Conectando Claude y VSCode a Herramientas Externas</title>
      <dc:creator>Renzo Fernando LOYOLA VILCA CHOQUE</dc:creator>
      <pubDate>Thu, 04 Dec 2025 01:16:02 +0000</pubDate>
      <link>https://dev.to/renzo_fernandoloyolavil/building-an-mcp-server-connecting-claude-and-vscode-to-external-tools-1g4c</link>
      <guid>https://dev.to/renzo_fernandoloyolavil/building-an-mcp-server-connecting-claude-and-vscode-to-external-tools-1g4c</guid>
      <description>&lt;h2&gt;
  
  
  Introducción
&lt;/h2&gt;

&lt;p&gt;El Protocolo de Contexto de Modelo (MCP) es un protocolo abierto revolucionario desarrollado por Anthropic que permite a asistentes de IA como Claude conectarse con fuentes de datos externas y herramientas. En este artículo, te guiaré a través de la construcción de tu propio servidor MCP que puede ser utilizado con Claude Desktop, VSCode y otros clientes compatibles.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es MCP?
&lt;/h2&gt;

&lt;p&gt;MCP proporciona una forma estandarizada para que los asistentes de IA interactúen con sistemas externos. Piensa en él como un adaptador universal que permite a Claude:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Acceder a bases de datos y APIs&lt;/li&gt;
&lt;li&gt;Leer y escribir archivos&lt;/li&gt;
&lt;li&gt;Ejecutar comandos&lt;/li&gt;
&lt;li&gt;Interactuar con servicios web&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El protocolo define una arquitectura cliente-servidor donde:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clientes MCP&lt;/strong&gt; (como Claude Desktop o VSCode) se conectan a servidores&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Servidores MCP&lt;/strong&gt; exponen capacidades específicas (recursos, herramientas y prompts)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;La comunicación&lt;/strong&gt; ocurre a través de JSON-RPC 2.0 sobre stdio o HTTP&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Descripción General de la Arquitectura
&lt;/h2&gt;

&lt;p&gt;Un servidor MCP consta de tres componentes principales:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Recursos
&lt;/h3&gt;

&lt;p&gt;Los recursos son fuentes de datos que el servidor puede proporcionar a los clientes. Pueden ser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Archivos de un sistema de archivos&lt;/li&gt;
&lt;li&gt;Registros de bases de datos&lt;/li&gt;
&lt;li&gt;Respuestas de APIs&lt;/li&gt;
&lt;li&gt;Flujos de datos en tiempo real&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Herramientas
&lt;/h3&gt;

&lt;p&gt;Las herramientas son funciones que el cliente puede invocar a través del servidor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ejecutar comandos del sistema&lt;/li&gt;
&lt;li&gt;Realizar cálculos&lt;/li&gt;
&lt;li&gt;Interactuar con APIs externas&lt;/li&gt;
&lt;li&gt;Manipular datos&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Prompts
&lt;/h3&gt;

&lt;p&gt;Los prompts son plantillas predefinidas que ayudan a estructurar las interacciones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plantillas de consultas&lt;/li&gt;
&lt;li&gt;Patrones de comandos&lt;/li&gt;
&lt;li&gt;Instrucciones de flujo de trabajo&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Construyendo tu Primer Servidor MCP
&lt;/h2&gt;

&lt;p&gt;Construyamos un servidor MCP simple paso a paso. Para este ejemplo, usaré Python, pero los servidores MCP pueden construirse en cualquier lenguaje.&lt;/p&gt;

&lt;h3&gt;
  
  
  Requisitos Previos
&lt;/h3&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;mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Estructura Básica del Servidor
&lt;/h3&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;mcp.server&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Tool&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&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;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-mcp-server&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.list_resources&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;list_resources&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;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;Resource&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="nc"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;uri&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:///example.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Archivo de Ejemplo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;mimeType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text/plain&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="nd"&gt;@app.read_resource&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;read_resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;uri&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:///example.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;¡Hola desde el Servidor MCP!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&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;Recurso desconocido: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@app.list_tools&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;list_tools&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;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;Tool&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="nc"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;saludar&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Saludar a alguien por su nombre&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;inputSchema&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;type&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;object&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;properties&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nombre&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&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;string&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nombre&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="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nd"&gt;@app.call_tool&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;call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;saludar&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;¡Hola, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nombre&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&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;Herramienta desconocida: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&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;run&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conectando a Claude Desktop
&lt;/h2&gt;

&lt;p&gt;Para usar tu servidor MCP con Claude Desktop, necesitas configurarlo en la configuración de Claude:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Abre la configuración de Claude Desktop&lt;/li&gt;
&lt;li&gt;Navega a la sección "Developer"&lt;/li&gt;
&lt;li&gt;Agrega la configuración de tu servidor:
&lt;/li&gt;
&lt;/ol&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;"mcpServers"&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;"mi-servidor"&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;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"python"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&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="s2"&gt;"ruta/a/tu/servidor.py"&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Reinicia Claude Desktop&lt;/li&gt;
&lt;li&gt;Las herramientas y recursos de tu servidor ahora estarán disponibles para Claude&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conectando a VSCode
&lt;/h2&gt;

&lt;p&gt;Para la integración con VSCode, puedes usar la extensión MCP:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Instala la extensión MCP desde el marketplace&lt;/li&gt;
&lt;li&gt;Configura tu servidor en &lt;code&gt;.vscode/mcp.json&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&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;"servers"&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mi-servidor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"python"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&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="s2"&gt;"ruta/a/tu/servidor.py"&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="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;
  
  
  Casos de Uso del Mundo Real
&lt;/h2&gt;

&lt;p&gt;Aquí hay algunas aplicaciones prácticas para servidores MCP:&lt;/p&gt;

&lt;h3&gt;
  
  
  Acceso a Bases de Datos
&lt;/h3&gt;

&lt;p&gt;Crea un servidor que permita a Claude consultar tus bases de datos de forma segura:&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="nd"&gt;@app.list_tools&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;list_tools&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="nc"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;consultar_bd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ejecutar consultas SQL&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;h3&gt;
  
  
  Operaciones del Sistema de Archivos
&lt;/h3&gt;

&lt;p&gt;Construye un servidor que gestione archivos de proyecto:&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="nd"&gt;@app.list_resources&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;list_resources&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="nc"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&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;file:///&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;archivo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;archivo&lt;/span&gt; &lt;span class="ow"&gt;in&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;listdir&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Integración con APIs
&lt;/h3&gt;

&lt;p&gt;Conecta Claude a APIs externas:&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="nd"&gt;@app.call_tool&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;call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;obtener_datos&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&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;http_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mejores Prácticas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Seguridad Primero&lt;/strong&gt;: Siempre valida las entradas y sanitiza las salidas&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manejo de Errores&lt;/strong&gt;: Proporciona mensajes de error claros&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentación&lt;/strong&gt;: Documenta tus herramientas y recursos exhaustivamente&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rendimiento&lt;/strong&gt;: Usa async/await para operaciones de I/O&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pruebas&lt;/strong&gt;: Prueba tu servidor con diferentes clientes&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Repositorio de Ejemplo
&lt;/h2&gt;

&lt;p&gt;Puedes encontrar un ejemplo completo y funcional en mi repositorio de GitHub:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repositorio&lt;/strong&gt;: &lt;a href="https://github.com/renzoloyola/MCP-Server" rel="noopener noreferrer"&gt;https://github.com/renzoloyola/MCP-Server&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este repositorio incluye:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implementación básica del servidor MCP&lt;/li&gt;
&lt;li&gt;Ejemplos de configuración para Claude y VSCode&lt;/li&gt;
&lt;li&gt;Documentación e instrucciones de configuración&lt;/li&gt;
&lt;li&gt;Casos de uso de ejemplo&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Construir servidores MCP abre posibilidades infinitas para extender las capacidades de los asistentes de IA. Ya sea que te estés conectando a bases de datos, sistemas de archivos o APIs externas, MCP proporciona una forma estandarizada y poderosa de hacer que tus datos y herramientas sean accesibles para la IA.&lt;/p&gt;

&lt;p&gt;El Protocolo de Contexto de Modelo sigue evolucionando, y el ecosistema está creciendo rápidamente. Al crear tus propios servidores MCP, puedes personalizar Claude y otros clientes compatibles para que se ajusten a tus necesidades y flujos de trabajo específicos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recursos
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;Documentación MCP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/anthropics/anthropic-quickstarts" rel="noopener noreferrer"&gt;GitHub de Anthropic MCP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/renzoloyola/MCP-Server" rel="noopener noreferrer"&gt;Mi Repositorio de Ejemplo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;¿Has construido un servidor MCP? ¡Comparte tu experiencia en los comentarios!&lt;/p&gt;

</description>
      <category>mcpclaudevscodeai</category>
    </item>
  </channel>
</rss>
