<?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: REV</title>
    <description>The latest articles on DEV Community by REV (@3rev).</description>
    <link>https://dev.to/3rev</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%2F1505629%2F9fbad4c7-0a08-47b2-b253-fb1f317125da.jpeg</url>
      <title>DEV Community: REV</title>
      <link>https://dev.to/3rev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/3rev"/>
    <language>en</language>
    <item>
      <title>Kubernetes Ingress: HTTP and HTTPS Traffic Management</title>
      <dc:creator>REV</dc:creator>
      <pubDate>Sun, 04 Oct 2026 08:33:01 +0000</pubDate>
      <link>https://dev.to/3rev/kubernetes-ingress-http-and-https-traffic-management-4jo5</link>
      <guid>https://dev.to/3rev/kubernetes-ingress-http-and-https-traffic-management-4jo5</guid>
      <description>&lt;p&gt;Read the full article on &lt;a href="https://ehikioyaraeva.medium.com/how-to-implement-kubernetes-ingress-for-http-and-https-traffic-management-4494a45fbfdc" rel="noopener noreferrer"&gt;medium&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A hands-on Kubernetes infrastructure project demonstrating how to expose a web application through Kubernetes Ingress, route HTTP/HTTPS traffic with Contour and Envoy, provision infrastructure with Terraform, configure DNS, and automate TLS certificates with cert-manager and Let's Encrypt.&lt;/p&gt;

&lt;p&gt;The project was built and documented as a practical infrastructure walkthrough, with configuration files, terminal commands, Kubernetes resources, and runtime output used to verify each stage of the deployment.&lt;/p&gt;

&lt;p&gt;Architecture:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    Client["Internet&amp;lt;br/&amp;gt;HTTP / HTTPS"] --&amp;gt; LB["Google Cloud&amp;lt;br/&amp;gt;Load Balancer"]

    DNS["DNS"] --&amp;gt; LB
    LB --&amp;gt; Ingress["Kubernetes Ingress&amp;lt;br/&amp;gt;Contour"]
    Ingress --&amp;gt; Envoy["Envoy&amp;lt;br/&amp;gt;Proxy / Routing"]
    Envoy --&amp;gt; Service["ClusterIP&amp;lt;br/&amp;gt;Service"]
    Service --&amp;gt; Pods["Nginx Pods&amp;lt;br/&amp;gt;Web Server"]

    CM["cert-manager"] --&amp;gt; LE["Let's Encrypt"]
    LE --&amp;gt; Cert["TLS Certificate"]
    Cert --&amp;gt; Ingress&lt;/code&gt;&lt;/pre&gt;



&lt;h2&gt;
  
  
  What this project demonstrates
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Provisioning a Google Kubernetes Engine (GKE) cluster with Terraform&lt;/li&gt;
&lt;li&gt;Connecting to and validating a Kubernetes cluster with "gcloud" and "kubectl"&lt;/li&gt;
&lt;li&gt;Installing Contour as a Kubernetes Ingress controller&lt;/li&gt;
&lt;li&gt;Using Envoy as the data-plane proxy&lt;/li&gt;
&lt;li&gt;Deploying an Nginx web application&lt;/li&gt;
&lt;li&gt;Exposing the application internally with a "ClusterIP" Service&lt;/li&gt;
&lt;li&gt;Routing external traffic through an Ingress resource&lt;/li&gt;
&lt;li&gt;Assigning and validating an external load balancer IP&lt;/li&gt;
&lt;li&gt;Configuring DNS for the Ingress endpoint&lt;/li&gt;
&lt;li&gt;Installing cert-manager&lt;/li&gt;
&lt;li&gt;Issuing TLS certificates through Let's Encrypt&lt;/li&gt;
&lt;li&gt;Configuring HTTPS on the Ingress&lt;/li&gt;
&lt;li&gt;Verifying Kubernetes resources and certificate status from the command line&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Technology Stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Kubernetes&lt;/td&gt;
&lt;td&gt;Container orchestration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Kubernetes Engine (GKE)&lt;/td&gt;
&lt;td&gt;Managed Kubernetes cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terraform&lt;/td&gt;
&lt;td&gt;Infrastructure provisioning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contour&lt;/td&gt;
&lt;td&gt;Kubernetes Ingress controller&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Envoy&lt;/td&gt;
&lt;td&gt;Layer 7 proxy and traffic routing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nginx&lt;/td&gt;
&lt;td&gt;Example web application&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cert-manager&lt;/td&gt;
&lt;td&gt;TLS certificate lifecycle management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Let's Encrypt&lt;/td&gt;
&lt;td&gt;Certificate authority&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNS / DDNS&lt;/td&gt;
&lt;td&gt;Domain-to-IP resolution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kubectl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Kubernetes administration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gcloud&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Google Cloud authentication and cluster access&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;

&lt;p&gt;Click &lt;a href="https://github.com/30Piraten/ingress-http-dev" rel="noopener noreferrer"&gt;Kubernetes Ingress&lt;/a&gt; to access GitHub repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── terraform/
│   ├── gke-cluster.tf
│   ├── variables.tf
│   └── ...
│
├── kubernetes/
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── ingress-updated.yaml
│   ├── letsencrypt-cm-issuer.yaml
│   └── certificate.yaml
│
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deployment Flow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Provision the GKE Cluster
&lt;/h3&gt;

&lt;p&gt;Terraform is used to define and provision the Google Kubernetes Engine infrastructure.&lt;/p&gt;

&lt;p&gt;Initialize and validate the Terraform configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform init
terraform validate
terraform &lt;span class="nb"&gt;fmt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply the configuration:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;The infrastructure creates the Kubernetes environment required for the remainder of the deployment.&lt;/p&gt;

&lt;p&gt;The original implementation also configured the cluster's service account and node pool through Terraform.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Connect to the Cluster
&lt;/h3&gt;

&lt;p&gt;Authenticate with Google Cloud:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud auth login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retrieve the cluster credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud container clusters get-credentials &amp;lt;cluster_name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--zone&lt;/span&gt; &amp;lt;zone_name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--project&lt;/span&gt; &amp;lt;project_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Validate the connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get nodes &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example runtime output from the original deployment showed two GKE nodes in the "Ready" state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME                                   STATUS   VERSION
gke-dev-cluster-gke-np-...             Ready    v1.30.3-gke.1639000
gke-dev-cluster-gke-np-...             Ready    v1.30.3-gke.1639000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This provides runtime evidence that the cluster was provisioned successfully and was accessible through &lt;code&gt;"kubectl".&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Install Contour
&lt;/h3&gt;

&lt;p&gt;Contour is deployed as the Kubernetes Ingress controller.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; contour.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the controller and Envoy workloads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; projectcontour &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The deployment produced Contour and Envoy workloads across the GKE nodes.&lt;/p&gt;

&lt;p&gt;The runtime output included:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;contour-...    1/1   Running
contour-...    1/1   Running
envoy-...      2/2   Running
envoy-...      2/2   Running
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This verifies that both the control-plane components and Envoy proxy instances were running successfully.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Deploy the Nginx Application
&lt;/h3&gt;

&lt;p&gt;The application uses Nginx.&lt;/p&gt;

&lt;p&gt;Apply the deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; deployment.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the Kubernetes Service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; service.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application is exposed internally through a "ClusterIP" Service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gore-svc&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIP&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gore&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"ClusterIP" keeps the application service internal to the cluster. Contour/Envoy provides the external entry point and routes requests to this service.&lt;/p&gt;

&lt;p&gt;Verify the service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get services &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;
gore-svc   ClusterIP   34.118.238.166  &amp;lt;none&amp;gt;        80/TCP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Configure the Ingress
&lt;/h3&gt;

&lt;p&gt;The Ingress resource connects the external traffic path to the internal application service.&lt;/p&gt;

&lt;p&gt;Apply the configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; ingress.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the Ingress:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get ingress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output from the deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME           CLASS     HOSTS   ADDRESS          PORTS
gore-ingress   contour   &lt;span class="k"&gt;*&lt;/span&gt;       35.229.120.117   80,443
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The external address is assigned to the load balancer managed by the Contour/Envoy deployment.&lt;/p&gt;

&lt;p&gt;Inspect the Envoy service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get &lt;span class="nt"&gt;-n&lt;/span&gt; projectcontour service envoy &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME    TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)
envoy   LoadBalancer   34.118.236.21   35.229.120.117   80:30899/TCP,443:31661/TCP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, the application can be reached through the external load balancer address.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Configure DNS
&lt;/h3&gt;

&lt;p&gt;The external load balancer IP needs to be associated with a domain name before HTTPS can be configured cleanly.&lt;/p&gt;

&lt;p&gt;The original implementation used a DDNS provider to create a DNS record pointing to the external IP.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    Domain["gore2.example-domain"] --&amp;gt;|DNS resolution| IP["35.229.120.117"]
    IP --&amp;gt;|HTTP / HTTPS| LB["Google Cloud Load Balancer"]
    LB --&amp;gt;|Ingress traffic| Contour["Contour"]
    Contour --&amp;gt;|Proxy / routing| Envoy["Envoy"]
    Envoy --&amp;gt;|Forward request| Service["Nginx Service"]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Verify that the DNS record resolves to the external address before proceeding with certificate issuance.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Install cert-manager
&lt;/h3&gt;

&lt;p&gt;Install cert-manager into the cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; cert-manager.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the cert-manager workloads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; cert-manager
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;cert-manager manages the lifecycle of the TLS certificate and Kubernetes Secret used by the Ingress.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Configure Let's Encrypt
&lt;/h3&gt;

&lt;p&gt;Create an Issuer for the Let's Encrypt production environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cert-manager.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Issuer&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;letsencrypt-production&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;acme&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://acme-v02.api.letsencrypt.org/directory&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your-email&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;privateKeySecretRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;letsencrypt-production&lt;/span&gt;
    &lt;span class="na"&gt;solvers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http01&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gore-ingress&lt;/span&gt;
            &lt;span class="na"&gt;ingressClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;contour&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply the configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; letsencrypt-cm-issuer.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the Issuer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe issuer letsencrypt-production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The original deployment returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Reason: ACMEAccountRegistered
Status: True
Type: Read
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This confirms that the ACME account was successfully registered with Let's Encrypt.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Create the TLS Certificate
&lt;/h3&gt;

&lt;p&gt;Create a Kubernetes "Certificate" resource:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cert-manager.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Certificate&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gore-tls&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gore-tls&lt;/span&gt;
  &lt;span class="na"&gt;issuerRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;letsencrypt-production&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Issuer&lt;/span&gt;
  &lt;span class="na"&gt;commonName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your-domain.example"&lt;/span&gt;
  &lt;span class="na"&gt;dnsNames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your-domain.example"&lt;/span&gt;
  &lt;span class="na"&gt;usages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;digital signature&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;key encipherment&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;server auth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; certificate.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the certificate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe certificate gore-tls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The original deployment reported:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Message: Certificate is up to &lt;span class="nb"&gt;date &lt;/span&gt;and has not expired
Reason:  Ready
Status:  True
Type:    Ready
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The certificate resource also exposed its validity and renewal timestamps through Kubernetes status information.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Enable HTTPS on the Ingress
&lt;/h3&gt;

&lt;p&gt;Update the Ingress configuration to reference the TLS Secret created by cert-manager.&lt;/p&gt;

&lt;p&gt;Apply the updated configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; ingress-updated.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the Ingress:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get ingress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME           CLASS     HOSTS                  ADDRESS          PORTS
gore-ingress   contour   your-domain.example    &amp;lt;external-ip&amp;gt;   80,443
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this stage, traffic follows the HTTPS path:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    Client["Client"] --&amp;gt;|HTTPS| DNS["DNS"]
    DNS --&amp;gt; LB["External Load Balancer"]
    LB --&amp;gt; CE["Contour / Envoy"]
    CE --&amp;gt;|TLS termination| Service["ClusterIP Service"]
    Service --&amp;gt; Nginx["Nginx"]&lt;/code&gt;&lt;/pre&gt;



&lt;h2&gt;
  
  
  Verification Checklist
&lt;/h2&gt;

&lt;p&gt;The deployment was verified progressively rather than treating "terraform apply" or "kubectl apply" as proof of success.&lt;/p&gt;

&lt;h2&gt;
  
  
  Infrastructure
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[x] GKE cluster provisioned with Terraform&lt;/li&gt;
&lt;li&gt;[x] Cluster credentials configured&lt;/li&gt;
&lt;li&gt;[x] Kubernetes nodes reachable&lt;/li&gt;
&lt;li&gt;[x] Nodes reported "Ready"&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Ingress
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[x] Contour installed&lt;/li&gt;
&lt;li&gt;[x] Envoy deployed&lt;/li&gt;
&lt;li&gt;[x] Envoy service exposed through a load balancer&lt;/li&gt;
&lt;li&gt;[x] Ingress resource created&lt;/li&gt;
&lt;li&gt;[x] External IP assigned&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Application
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[x] Nginx deployment created&lt;/li&gt;
&lt;li&gt;[x] "ClusterIP" service created&lt;/li&gt;
&lt;li&gt;[x] Ingress routed traffic to the application&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DNS
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[x] DNS record created&lt;/li&gt;
&lt;li&gt;[x] DNS mapped to the external load balancer address&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  TLS
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[x] cert-manager installed&lt;/li&gt;
&lt;li&gt;[x] Let's Encrypt Issuer configured&lt;/li&gt;
&lt;li&gt;[x] ACME account registered&lt;/li&gt;
&lt;li&gt;[x] Certificate resource created&lt;/li&gt;
&lt;li&gt;[x] Certificate reported "Ready"&lt;/li&gt;
&lt;li&gt;[x] Ingress configured for HTTPS&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This project demonstrates the relationship between several infrastructure layers that are often documented independently:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    Terraform["Terraform"] --&amp;gt; GKE["GKE"]
    GKE --&amp;gt; Kubernetes["Kubernetes"]

    Kubernetes --&amp;gt; Deployment["Deployment"]
    Deployment --&amp;gt; Nginx["Nginx"]

    Kubernetes --&amp;gt; Service["Service"]
    Service --&amp;gt; ClusterIP["ClusterIP"]

    Kubernetes --&amp;gt; Ingress["Ingress"]
    Ingress --&amp;gt; Contour["Contour"]
    Contour --&amp;gt; Envoy["Envoy"]
    Envoy --&amp;gt; LB["Load Balancer"]
    LB --&amp;gt; DNS["DNS"]
    DNS --&amp;gt; HTTPS["HTTPS"]
    HTTPS --&amp;gt; CertManager["cert-manager"]
    CertManager --&amp;gt; LetsEncrypt["Let's Encrypt"]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The main takeaway is that Kubernetes Ingress is not an isolated resource. It sits inside a larger request path involving DNS, load balancing, ingress controllers, services, application workloads, and TLS infrastructure.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>infrastructure</category>
      <category>webdev</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Contract-First Architecture: Governing Microservice Boundaries with OpenAPI 3.2 and Spectral</title>
      <dc:creator>REV</dc:creator>
      <pubDate>Sun, 04 Oct 2026 08:09:42 +0000</pubDate>
      <link>https://dev.to/3rev/contract-first-architecture-governing-microservice-boundaries-with-openapi-32-and-spectral-lb</link>
      <guid>https://dev.to/3rev/contract-first-architecture-governing-microservice-boundaries-with-openapi-32-and-spectral-lb</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In a distributed system, an API contract is more than documentation.&lt;/p&gt;

&lt;p&gt;It defines the boundary between services and tells consumers what data they can send, what data they can receive, and which representations are considered valid.&lt;/p&gt;

&lt;p&gt;When an implementation and its contract drift apart, consumers begin to depend on behavior that may no longer be guaranteed. Frontends, mobile applications, and downstream services can end up reverse-engineering behavior from implementation details instead of relying on an explicit contract.&lt;/p&gt;

&lt;p&gt;This is one reason contract-first API design is useful.&lt;/p&gt;

&lt;p&gt;In a contract-first approach, the API specification is designed before the implementation. The specification becomes a shared scope that developers, consumers, reviewers, and tooling can reuse.&lt;/p&gt;

&lt;p&gt;This article explores how OpenAPI 3.2 can be used to model strict API contracts, represent state-dependent resources, standardize error responses with RFC 9457 Problem Details, and enforce API conventions with Spectral and GitHub Actions.&lt;/p&gt;

&lt;p&gt;The aim is not to use every feature OpenAPI provides. But to make repeatable rules enforceable.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this article covers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Strict schema modeling with OpenAPI 3.2&lt;/li&gt;
&lt;li&gt;Modeling state-dependent resources with "oneOf" and "allOf"&lt;/li&gt;
&lt;li&gt;The role of "discriminator" in polymorphic schemas&lt;/li&gt;
&lt;li&gt;The relationship between OpenAPI 3.2 and JSON Schema Draft 2020-12&lt;/li&gt;
&lt;li&gt;Standardizing API errors with RFC 9457&lt;/li&gt;
&lt;li&gt;Modeling a payment lifecycle as an API contract&lt;/li&gt;
&lt;li&gt;Turning API conventions into Spectral rules&lt;/li&gt;
&lt;li&gt;Running those rules locally and in CI/CD&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;You should have a basic understanding of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP methods and status codes&lt;/li&gt;
&lt;li&gt;REST APIs&lt;/li&gt;
&lt;li&gt;YAML&lt;/li&gt;
&lt;li&gt;JSON Schema&lt;/li&gt;
&lt;li&gt;OpenAPI&lt;/li&gt;
&lt;li&gt;Git and GitHub Actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The examples use OpenAPI 3.2.1.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Contract-First Architecture
&lt;/h2&gt;

&lt;p&gt;There are two common approaches to designing APIs: code-first and contract-first.&lt;/p&gt;

&lt;p&gt;In a code-first design, developers begin with implementation and generate or derive the API specification from the resulting code.&lt;/p&gt;

&lt;p&gt;In a contract-first approach, the API interface is defined before implementation.&lt;/p&gt;

&lt;p&gt;Neither approach eliminates the need for business logic. The difference is where the API boundary is established.&lt;/p&gt;

&lt;p&gt;Consider a service that exposes a withdrawal operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;POST /accounts/005/withdraw
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A code-first implementation might define the request structure inside the application and expose the resulting endpoint.&lt;/p&gt;

&lt;p&gt;A contract-first design starts by describing the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
  &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
      &lt;span class="na"&gt;minimum&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
    &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
      &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ZAR&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;USD&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;EUR&lt;/span&gt;
  &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;amount&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;currency&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contract now establishes several rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"amount" must be an integer.&lt;/li&gt;
&lt;li&gt;"amount" must be at least "100".&lt;/li&gt;
&lt;li&gt;"currency" must be one of the permitted values.&lt;/li&gt;
&lt;li&gt;Both fields are required.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The API boundary therefore rejects representations that violate these constraints before they reach the deeper application logic.&lt;/p&gt;

&lt;p&gt;This distinction matters.&lt;/p&gt;

&lt;p&gt;A schema can deny a misrepresented data. It cannot, by itself, determine whether a business operation or logic is permitted.&lt;/p&gt;

&lt;p&gt;For example, a schema can establish that a withdrawal contains a valid amount. The application must still determine whether the account has sufficient funds, whether the account is active, and whether the withdrawal is permitted at the point of request.&lt;/p&gt;

&lt;p&gt;This gives us a useful separation:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    Contract["API contract"]
    ContractQuestion["What does valid data look like?"]

    Schema["Schema validation"]
    SchemaQuestion["Does the request have a valid representation?"]

    Application["Application logic"]
    ApplicationQuestion["Is the operation permitted?"]

    Domain["Domain state transition"]

    Contract --&amp;gt; ContractQuestion
    ContractQuestion --&amp;gt; Schema
    Schema --&amp;gt; SchemaQuestion
    SchemaQuestion --&amp;gt; Application
    Application --&amp;gt; ApplicationQuestion
    ApplicationQuestion --&amp;gt; Domain&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The contract establishes the scope.&lt;/p&gt;

&lt;p&gt;The application establishes the behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Strict Schema Modeling
&lt;/h2&gt;

&lt;p&gt;Strict schema modeling helps make the set of valid API representations explicit.&lt;/p&gt;

&lt;p&gt;Consider an account resource:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"accountStatus"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"active"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"balance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ZAR"&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;p&gt;This representation contains state that may influence what operations the client can perform.&lt;/p&gt;

&lt;p&gt;If an API accepts a poorly defined scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the contract says very little about what makes up a valid instance.&lt;/p&gt;

&lt;p&gt;A stricter schema can define the expected structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
&lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;accountStatus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
    &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;active&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;suspended&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;closed&lt;/span&gt;

  &lt;span class="na"&gt;balance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
    &lt;span class="na"&gt;minimum&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

  &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
    &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ZAR&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;USD&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;EUR&lt;/span&gt;

&lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;accountStatus&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;balance&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;currency&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the API contract describes a much smaller set of valid representations.&lt;/p&gt;

&lt;p&gt;This is useful because downstream consumers no longer have to infer the shape of the resource from implementation behavior.&lt;/p&gt;

&lt;p&gt;The important principle is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A strict schema should express meaningful domain constraints, not merely add keywords for the sake of strictness.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  3. Modeling State With Polymorphism
&lt;/h2&gt;

&lt;p&gt;Some resources do not have the same representation in every state.&lt;/p&gt;

&lt;p&gt;An account can be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;Account&lt;/span&gt;
&lt;span class="s"&gt;├── Pending&lt;/span&gt;
&lt;span class="s"&gt;├── Verified&lt;/span&gt;
&lt;span class="s"&gt;└── Suspended&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each state may have different required properties.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;A pending account may require a name.&lt;/li&gt;
&lt;li&gt;A verified account may also require "verifiedAt".&lt;/li&gt;
&lt;li&gt;A suspended account may addtionally require "suspendedAt".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OpenAPI supports composition through JSON Schema keywords such as "oneOf" and "allOf".&lt;/p&gt;

&lt;p&gt;A simplified model looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schemas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;AccountBase&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
      &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;status&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
          &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PENDING&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;VERIFIED&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SUSPENDED&lt;/span&gt;

    &lt;span class="na"&gt;Account&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;oneOf&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Pending'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Verified'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Suspended'&lt;/span&gt;

      &lt;span class="na"&gt;discriminator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;propertyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;status&lt;/span&gt;
        &lt;span class="na"&gt;mapping&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;PENDING&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Pending'&lt;/span&gt;
          &lt;span class="na"&gt;VERIFIED&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Verified'&lt;/span&gt;
          &lt;span class="na"&gt;SUSPENDED&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Suspended'&lt;/span&gt;

    &lt;span class="na"&gt;Pending&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;allOf&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/AccountBase'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
          &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;name&lt;/span&gt;

    &lt;span class="na"&gt;Verified&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;allOf&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/AccountBase'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
          &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
            &lt;span class="na"&gt;verifiedAt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
              &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;date-time&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;name&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;verifiedAt&lt;/span&gt;

    &lt;span class="na"&gt;Suspended&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;allOf&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/AccountBase'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
          &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
            &lt;span class="na"&gt;suspendedAt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
              &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;date-time&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;name&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;suspendedAt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model separates common properties from state-specific properties.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;"AccountBase" contains information common to all states.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"Pending", "Verified", and "Suspended" extend that base representation with state-specific requirements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"oneOf" then defines the possible representations of "Account".&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What "oneOf" does:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"oneOf" requires the instance to validate against exactly one of the listed schemas.&lt;/p&gt;

&lt;p&gt;That makes it useful when the states represent a different format.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Account&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;oneOf&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Pending'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Verified'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Suspended'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A payload should therefore match one and only one of those alternatives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What "allOf" does:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"allOf" combines schemas.&lt;/p&gt;

&lt;p&gt;This example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Verified&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allOf&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/AccountBase'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
      &lt;span class="s"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;means that a verified account must satisfy both the base schema and the additional verified-account schema.&lt;/p&gt;

&lt;p&gt;This is important when multiple states share a common structure but add different requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The Role of "discriminator"
&lt;/h2&gt;

&lt;p&gt;A common misconception is that "discriminator" performs the validation. It does not.&lt;/p&gt;

&lt;p&gt;OpenAPI 3.2.1 defines the discriminator as a hint that helps identify which schema is expected to validate a polymorphic payload. It does not change the validation outcome.&lt;/p&gt;

&lt;p&gt;In this snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;discriminator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;propertyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;status&lt;/span&gt;
  &lt;span class="na"&gt;mapping&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;PENDING&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Pending'&lt;/span&gt;
    &lt;span class="na"&gt;VERIFIED&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Verified'&lt;/span&gt;
    &lt;span class="na"&gt;SUSPENDED&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Suspended'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the "status" property tells consumers which schema corresponds to the payload.&lt;/p&gt;

&lt;p&gt;The actual validation still comes from "oneOf".&lt;/p&gt;

&lt;p&gt;The difference becomes clear:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;oneOf
  │
  └── defines the validation alternatives

discriminator
  │
  └── helps identify the expected alternative
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A useful rule is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use "discriminator" when it improves the representation, serialization, deserialization, or consumer experience of a polymorphic model. Do not introduce it simply because the model contains multiple schemas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  5. Schema Validation Is Not Domain Logic
&lt;/h2&gt;

&lt;p&gt;Strict schemas can describe valid representations of domain state.&lt;/p&gt;

&lt;p&gt;They cannot, by themselves, enforce every state transition.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Verified&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allOf&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/AccountBase'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;verifiedAt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
          &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;date-time&lt;/span&gt;
      &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;verifiedAt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following representation is invalid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VERIFIED"&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;p&gt;because "verifiedAt" is required by the "Verified" schema.&lt;/p&gt;

&lt;p&gt;This representation satisfies the schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VERIFIED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"verifiedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-09-22T10:30:00Z"&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;p&gt;But schema validation still does not answer a very important question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Was this account actually allowed to transition from "PENDING" to "VERIFIED"?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That decision belongs to your application.&lt;/p&gt;

&lt;p&gt;The core differences can be summarized as:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Responsible layer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Data type&lt;/td&gt;
&lt;td&gt;Schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Required fields&lt;/td&gt;
&lt;td&gt;Schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Allowed values&lt;/td&gt;
&lt;td&gt;Schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Representation of a state&lt;/td&gt;
&lt;td&gt;Schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Whether a transition is permitted&lt;/td&gt;
&lt;td&gt;Application/domain logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authorization&lt;/td&gt;
&lt;td&gt;Application/security layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database transaction&lt;/td&gt;
&lt;td&gt;Application/data layer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This boundary is necessary because an API specification should not be treated as a replacement for domain logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. OpenAPI 3.2 and JSON Schema
&lt;/h2&gt;

&lt;p&gt;OpenAPI 3.2.1 defines the Schema Object as a superset of JSON Schema Draft 2020-12. Unless OpenAPI adds specific semantics, Schema Object keywords follow JSON Schema behavior.&lt;/p&gt;

&lt;p&gt;This provides a fine tuned schema vocabulary than treating an API specification as a simple description of field names and types.&lt;/p&gt;

&lt;p&gt;This specification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;50000&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;currency"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ZAR"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;metadata"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;can be modeled using rules that describe what constitutes a valid instance.&lt;/p&gt;

&lt;p&gt;The difference is between:&lt;/p&gt;

&lt;p&gt;describing an approximate payload shape and defining the set of representations the API accepts or produces.&lt;/p&gt;

&lt;p&gt;A schema can make this decision very precise.&lt;/p&gt;

&lt;p&gt;However, JSON Schema validation still operates on the representation.&lt;/p&gt;

&lt;p&gt;It does not know whether a payment should be settled, whether a user is authorized to settle it, or whether a transaction violates a business decision.&lt;/p&gt;

&lt;p&gt;It is worth mentioning that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Schema validation protects the API scope; domain logic protects the business rules behind it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  7. Standardizing Errors With RFC 9457
&lt;/h2&gt;

&lt;p&gt;HTTP status codes communicate the broad outcome of an HTTP request, but they do not always provide enough information for a client to understand a specific application problem.&lt;/p&gt;

&lt;p&gt;Imagine three regional services returning the same underlying failure in different formats:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    Client["Client"]
    Gateway["API Gateway"]

    ZA["South Africa Region"]
    EU["Europe Region"]
    US["US Region"]

    Payment["Payment Service"]

    Client --&amp;gt; Gateway
    Gateway --&amp;gt; ZA
    Gateway --&amp;gt; EU
    Gateway --&amp;gt; US

    ZA --&amp;gt; Payment
    EU --&amp;gt; Payment
    US --&amp;gt; Payment&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;South Africa might return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"payment_failed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"payment provider unavailable"&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;p&gt;Europe might return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SERVICE_PROVIDER_DOWN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"upstream unavailable"&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;p&gt;The US might return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"errorMessage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"temporary failure"&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;p&gt;The HTTP status may communicate a similar outcome, but the response bodies expose three different contracts.&lt;/p&gt;

&lt;p&gt;A client now needs separate handling logic for each representation.&lt;/p&gt;

&lt;p&gt;RFC 9457, Problem Details for HTTP APIs, provides a standardized structure for communicating machine-readable problem information.&lt;/p&gt;

&lt;p&gt;A problem response might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://api.example.com/problems/provider-unavailable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Payment provider unavailable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"detail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The payment provider is temporarily unavailable."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"instance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/payments/12345"&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;p&gt;The standard members communicate different pieces of information:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Member&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"type"&lt;/td&gt;
&lt;td&gt;Identifies the problem type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"title"&lt;/td&gt;
&lt;td&gt;Provides a short human-readable summary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"status"&lt;/td&gt;
&lt;td&gt;Indicates the HTTP status associated with the problem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"detail"&lt;/td&gt;
&lt;td&gt;Describes the specific occurrence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"instance"&lt;/td&gt;
&lt;td&gt;Identifies the particular occurrence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;RFC 9457 does not require every problem response to contain all five members. For example, "type" has a defined default of "about:blank" when or if you omit it.&lt;/p&gt;

&lt;p&gt;You can nevertheless choose to make these members mandatory as part of your own API policy.&lt;/p&gt;

&lt;p&gt;This gives you a specific outcome:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;RFC 9457 ── defines the problem-details model&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your API policy ── can impose stricter requirements&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Problem Details can also be extended with application-specific members:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://api.example.com/problems/provider-unavailable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Payment provider unavailable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"detail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Payment provider is temporarily unavailable."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"instance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/payments/12345"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eu-west-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"retryable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;p&gt;The additional members are application-specific extensions rather than standard RFC 9457 members.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Modeling an Enterprise Payment Contract
&lt;/h2&gt;

&lt;p&gt;We can now combine the concepts from earlier.&lt;/p&gt;

&lt;p&gt;Suppose a payment service has three lifecycle states:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    Unsettled["UNSETTLED"]
    Settled["SETTLED"]
    Failed["FAILED"]

    Unsettled --&amp;gt;|"POST /settle"| Settled
    Unsettled --&amp;gt;|"failure"| Failed&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Your API contract can describe the representations of those states while the application logic controls whether a transition is permitted.&lt;/p&gt;

&lt;p&gt;A simplified endpoint might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;openapi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3.2.1&lt;/span&gt;

&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Payment API&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.0.1&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="s"&gt;API contract for managing payment lifecycle states.&lt;/span&gt;

&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="s"&gt;/v1/payments/{paymentId}/settle&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Settle a payment&lt;/span&gt;
      &lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;settlePayment&lt;/span&gt;

      &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/parameters/PaymentId'&lt;/span&gt;

      &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;200'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Payment successfully settled.&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/SettledPayment'&lt;/span&gt;

      &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;409'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="s"&gt;The payment cannot be settled because its current&lt;/span&gt;
            &lt;span class="s"&gt;state does not permit settlement.&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;application/problem+json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/ProblemDetails'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resulting flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    Contract["API Contract"]
    State["Payment state model"]

    Unsettled["UNSETTLED"]
    Settled["SETTLED"]
    Failed["FAILED"]

    Domain["Domain logic"]

    Success["Success"]
    Failure["Failure"]

    Status200["200"]
    StatusError["409 / 422 / 503"]

    ProblemType["application/problem+json"]
    ProblemDetails["ProblemDetails"]

    Contract --&amp;gt; State

    State --&amp;gt; Unsettled
    State --&amp;gt; Settled
    State --&amp;gt; Failed

    Unsettled --&amp;gt;|"POST /settle"| Domain

    Domain --&amp;gt; Success
    Domain --&amp;gt; Failure

    Success --&amp;gt; Status200
    Failure --&amp;gt; StatusError

    StatusError --&amp;gt; ProblemType
    ProblemType --&amp;gt; ProblemDetails&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
dot&lt;/p&gt;

&lt;p&gt;This separation gives each layer a clear responsibility:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    OpenAPI["OpenAPI&amp;lt;br/&amp;gt;Defines the interface"]
    Schema["Schema&amp;lt;br/&amp;gt;Defines valid representations"]
    Application["Application&amp;lt;br/&amp;gt;Enforces business rules"]
    Domain["Domain logic&amp;lt;br/&amp;gt;Controls state transitions"]
    ProblemDetails["Problem Details&amp;lt;br/&amp;gt;Standardizes failure representation"]

    OpenAPI --&amp;gt; Schema
    Schema --&amp;gt; Application
    Application --&amp;gt; Domain
    Domain --&amp;gt; ProblemDetails&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;This scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;const&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SETTLED&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;means that an instance represented as "SettledPayment" must contain the value "SETTLED".&lt;/p&gt;

&lt;p&gt;It does not mean OpenAPI will prevent an application from changing a payment from "FAILED" to "SETTLED".&lt;/p&gt;

&lt;p&gt;That transition must be enforced by the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. From Documentation to Governance
&lt;/h2&gt;

&lt;p&gt;Imagine that your API has adopted RFC 9457 and now expects all error responses to use:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;application/problem+json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;#/components/schemas/ProblemDetails&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A new endpoint could accidentally introduce:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;409'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Error'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while the rest of the API uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;409'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;application/problem+json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/ProblemDetails'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A reviewer may catch the inconsistency in a small API.&lt;/p&gt;

&lt;p&gt;Trying to catch inconsistencies cross dozens of services and hundreds of operations, relying on manual review becomes difficult.&lt;/p&gt;

&lt;p&gt;This is where API governance tooling becomes useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Automating API Governance With Spectral
&lt;/h2&gt;

&lt;p&gt;Spectral can evaluate an OpenAPI document against a set of rules.&lt;/p&gt;

&lt;p&gt;Instead of merely documenting a convention:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;All error responses must use Problem Details.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;we can encode the requirement as an executable rule.&lt;/p&gt;

&lt;p&gt;This changes the diagram:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    Convention["Written convention"]
    Rule["Spectral rule"]
    Validation["Automated validation"]
    Feedback["Developer feedback"]
    CICD["CI/CD enforcement"]

    Convention --&amp;gt; Rule
    Rule --&amp;gt; Validation
    Validation --&amp;gt; Feedback
    Feedback --&amp;gt; CICD&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Click &lt;a href="https://github.com/30Piraten/technical-articles/blob/main/examples/openapi/.spectral.yaml" rel="noopener noreferrer"&gt;spectral ruleset&lt;/a&gt; for complete rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rule 1: Require Problem Details fields
&lt;/h3&gt;

&lt;p&gt;Your API policy can require the canonical "ProblemDetails" schema to contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"type"&lt;/li&gt;
&lt;li&gt;"title"&lt;/li&gt;
&lt;li&gt;"status"&lt;/li&gt;
&lt;li&gt;"detail"&lt;/li&gt;
&lt;li&gt;"instance"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Spectral rule can express that requirement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;problem-details-required-fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="s"&gt;The ProblemDetails schema must contain&lt;/span&gt;
    &lt;span class="s"&gt;type, title, status, detail, and instance.&lt;/span&gt;

  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="s"&gt;ProblemDetails must define type, title, status,&lt;/span&gt;
    &lt;span class="s"&gt;detail, and instance.&lt;/span&gt;

  &lt;span class="na"&gt;given&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$.components.schemas.ProblemDetails&lt;/span&gt;

  &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;error&lt;/span&gt;

  &lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required&lt;/span&gt;
      &lt;span class="na"&gt;function&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;schema&lt;/span&gt;
      &lt;span class="na"&gt;functionOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
          &lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;const&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;type&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required&lt;/span&gt;
      &lt;span class="na"&gt;function&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;schema&lt;/span&gt;
      &lt;span class="na"&gt;functionOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
          &lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;const&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;title&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required&lt;/span&gt;
      &lt;span class="na"&gt;function&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;schema&lt;/span&gt;
      &lt;span class="na"&gt;functionOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
          &lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;const&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;status&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required&lt;/span&gt;
      &lt;span class="na"&gt;function&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;schema&lt;/span&gt;
      &lt;span class="na"&gt;functionOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
          &lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;const&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;detail&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required&lt;/span&gt;
      &lt;span class="na"&gt;function&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;schema&lt;/span&gt;
      &lt;span class="na"&gt;functionOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
          &lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;const&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;instance&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rule has four valuable concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;given: WHERE does the rule apply?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;then: WHAT must be true?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;function: HOW is the condition evaluated?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;severity: WHAT happens when it fails?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Rule 2: Enforce the Error Schema Across the API
&lt;/h3&gt;

&lt;p&gt;The first rule checks the schema itself.&lt;/p&gt;

&lt;p&gt;The second rule checks how that schema is used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;error-response-problem-details&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="s"&gt;Every 4xx and 5xx response must reference&lt;/span&gt;
    &lt;span class="s"&gt;the ProblemDetails schema.&lt;/span&gt;

  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="s"&gt;All 4xx and 5xx responses must use&lt;/span&gt;
    &lt;span class="s"&gt;#/components/schemas/ProblemDetails.&lt;/span&gt;

  &lt;span class="na"&gt;given&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$.paths[*][*].responses[?(@property&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'400'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;@property&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'600')]"&lt;/span&gt;

  &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;error&lt;/span&gt;

  &lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;content.application/problem+json.schema.$ref&lt;/span&gt;
    &lt;span class="na"&gt;function&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pattern&lt;/span&gt;

    &lt;span class="na"&gt;functionOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^#/components/schemas/ProblemDetails$"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The JSONPath expression determines what Spectral examines.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;$.paths: every API path&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[*]: every path item&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[*]: every operation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;.responses: every response&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[?(@property &amp;gt;= '400' &amp;amp;&amp;amp; @property &amp;lt; '600')]: every 4xx and 5xx response&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rule then checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;content
  └── application/problem+json
        └── schema
              └── &lt;span class="nv"&gt;$ref&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and requires that reference to resolve to:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;#/components/schemas/ProblemDetails&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Rule 3: Enforce the Media Type
&lt;/h3&gt;

&lt;p&gt;The schema reference is only part of the convention.&lt;/p&gt;

&lt;p&gt;The response should also use the RFC 9457 media type: &lt;code&gt;application/problem+json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We can encode that requirement separately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;problem-details-media-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="s"&gt;Every 4xx and 5xx response must use&lt;/span&gt;
    &lt;span class="s"&gt;application/problem+json.&lt;/span&gt;

  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="s"&gt;Error responses must use the RFC 9457 media type&lt;/span&gt;
    &lt;span class="s"&gt;application/problem+json.&lt;/span&gt;

  &lt;span class="na"&gt;given&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$.paths[*][*].responses[?(@property&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'400'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;@property&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'600')].content"&lt;/span&gt;

  &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;error&lt;/span&gt;

  &lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/problem+json&lt;/span&gt;
    &lt;span class="na"&gt;function&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;truthy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The three rules now enforce different layers of the same policy:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    Rule1["Rule 1"] --&amp;gt; Check1["Is the canonical ProblemDetails schema complete?"]
    Check1 --&amp;gt; Rule2["Rule 2"]

    Rule2 --&amp;gt; Check2["Do error responses reference that schema?"]
    Check2 --&amp;gt; Rule3["Rule 3"]

    Rule3 --&amp;gt; Check3["Do error responses use the correct media type?"]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;This is where your documentation takes the right shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Running Spectral Locally
&lt;/h2&gt;

&lt;p&gt;Once the contract and ruleset exist, Spectral can validate the API description.&lt;/p&gt;

&lt;p&gt;Install the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @stoplight/spectral-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click &lt;a href="https://github.com/30Piraten/technical-articles/blob/main/examples/openapi/enterprise_payment_contract.yaml" rel="noopener noreferrer"&gt;enterprise payment contract&lt;/a&gt; to see full contract.&lt;/p&gt;

&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;spectral lint examples/openapi/enterprise_payment_contract.yaml &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;--ruleset&lt;/span&gt; examples/openapi/.spectral.yaml &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;--fail-severity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;warn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This contract should complete without rule violations.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now deliberately introduce an invalid reference:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ref: '#/components/schemas/Errors'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;instead of:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ref: '#/components/schemas/ProblemDetails'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Run the linter again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;spectral lint examples/openapi/enterprise_payment_contract.yaml &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;--ruleset&lt;/span&gt; examples/openapi/.spectral.yaml &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;--fail-severity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;warn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result should contain errors similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- error  error-response-problem-details
All 4xx and 5xx responses must use
&lt;span class="c"&gt;#/components/schemas/ProblemDetails.&lt;/span&gt;

- error  invalid-ref
&lt;span class="c"&gt;#/components/schemas/Errors does not exist.&lt;/span&gt;

- error  problem-details-required-fields
ProblemDetails must define &lt;span class="nb"&gt;type&lt;/span&gt;, title,
status, detail, and instance.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aside from the error message, the feedback loop is also important:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    Developer["Developer changes contract"]
    Spectral["Spectral evaluates contract"]
    Violation["Rule violation detected"]
    Feedback["Developer receives immediate feedback"]
    Corrected["Contract is corrected"]

    Developer --&amp;gt; Spectral
    Spectral --&amp;gt; Violation
    Violation --&amp;gt; Feedback
    Feedback --&amp;gt; Corrected
    Corrected --&amp;gt; Developer&lt;/code&gt;&lt;/pre&gt;



&lt;h2&gt;
  
  
  12. Enforcing the Contract in CI/CD
&lt;/h2&gt;

&lt;p&gt;Local validation is necessary, but sometimes developers can forget to run it.&lt;/p&gt;

&lt;p&gt;The same rules defined earlier can also be run in CI.&lt;/p&gt;

&lt;p&gt;A simplified GitHub Action specification looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;API Contract&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;spectral&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Spectral&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install -g @stoplight/spectral-cli&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lint OpenAPI contract&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;spectral lint \&lt;/span&gt;
            &lt;span class="s"&gt;examples/openapi/enterprise_payment_contract.yaml \&lt;/span&gt;
            &lt;span class="s"&gt;--ruleset examples/openapi/.spectral.yaml \&lt;/span&gt;
            &lt;span class="s"&gt;--fail-severity=warn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running a pull request activates the spectral linter and we see an error like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Run spectral lint enterprise_payment_contract.yaml &lt;span class="nt"&gt;--ruleset&lt;/span&gt; .spectral.yaml &lt;span class="nt"&gt;--fail-severity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;warn

/home/runner/work/technical-articles/technical-articles/enterprise_payment_contract.yaml

  37:23  error  error-response-problem-details
          All 4xx and 5xx responses must use &lt;span class="c"&gt;#/components/schemas/ProblemDetails.&lt;/span&gt;

  37:23  error  invalid-ref
          &lt;span class="s1"&gt;'#/componente/schemas/Errors'&lt;/span&gt; does not exist

 185:16  error  problem-details-required-fields
          ProblemDetails must define &lt;span class="nb"&gt;type&lt;/span&gt;, title, status, detail, and instance.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;a href="https://github.com/30Piraten/technical-articles/pull/3" rel="noopener noreferrer"&gt;failed PR&lt;/a&gt; for more information.&lt;/p&gt;

&lt;p&gt;This creates another valid restriction:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    Developer["Developer"]
    CLI["Spectral CLI"]
    Feedback["Local feedback"]
    Commit["Git commit"]
    PR["Pull request"]
    Actions["GitHub Actions"]
    Spectral["Spectral"]

    Pass["PASS"]
    Fail["FAIL"]
    Continue["Continue"]
    Fix["Fix contract"]

    Developer --&amp;gt; CLI
    CLI --&amp;gt; Feedback
    Feedback --&amp;gt; Commit
    Commit --&amp;gt; PR
    PR --&amp;gt; Actions
    Actions --&amp;gt; Spectral

    Spectral --&amp;gt; Pass
    Spectral --&amp;gt; Fail

    Pass --&amp;gt; Continue
    Fail --&amp;gt; Fix&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;GitHub Actions itself does not automatically prevent a merge. The rules defined produces a status check. Repository branch-protection rules can then require that check to pass before a pull request can be merged.&lt;/p&gt;

&lt;p&gt;This creates two validation boundaries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Developer boundary
    │
    └── Fast &lt;span class="nb"&gt;local &lt;/span&gt;feedback

Repository boundary
    │
    └── Automated PR validation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The value of this approach is not the number of OpenAPI features used. The value comes from connecting several layers of logic.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    API["API design"]
    OpenAPI["OpenAPI contract"]
    Schema["Schema constraints"]
    Domain["Domain state model"]
    Errors["Standardized error representation"]
    Spectral["Spectral governance"]
    CICD["CI/CD enforcement"]

    API --&amp;gt; OpenAPI
    OpenAPI --&amp;gt; Schema
    Schema --&amp;gt; Domain
    Domain --&amp;gt; Errors
    Errors --&amp;gt; Spectral
    Spectral --&amp;gt; CICD&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Each layer addresses a different problem.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAPI defines the interface.&lt;/li&gt;
&lt;li&gt;JSON Schema constrains data representations.&lt;/li&gt;
&lt;li&gt;Application logic enforces business rules and state transitions.&lt;/li&gt;
&lt;li&gt;RFC 9457 provides a standardized representation for HTTP API problems.&lt;/li&gt;
&lt;li&gt;Spectral turns API conventions into executable rules.&lt;/li&gt;
&lt;li&gt;CI/CD continuously applies those rules to proposed changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is not an API that is automatically correct. It is an API whose rule-based assumptions are explicit, testable, and easier to keep consistent as the system grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A contract-first API is more than a document describing endpoints. It is an concise representation of the boundary between systems.&lt;/p&gt;

&lt;p&gt;OpenAPI 3.2 provides the structure for describing that boundary. Its Schema Object builds on JSON Schema, allowing API authors to express increasingly precise rules over valid data representations. Polymorphic constructs such as "oneOf" and "allOf" can model resources whose representations differ by state, while "discriminator" can help consumers identify the expected schema without changing validation semantics.&lt;/p&gt;

&lt;p&gt;These schemas still have limits.&lt;/p&gt;

&lt;p&gt;They can describe valid representations, but they cannot replace application logic, authorization, transactions, or domain state-transition rules.&lt;/p&gt;

&lt;p&gt;For error responses, RFC 9457 provides a standardized Problem Details model. An organization can then impose additional requirements on top of that standard, such as requiring specific members or using a problem schema across its services.&lt;/p&gt;

&lt;p&gt;Finally, Spectral turns those conventions into executables.&lt;/p&gt;

&lt;p&gt;Instead of relying entirely on reviewers to notice contract drift, the repository can continuously evaluate the specification against explicit rules. Running those rules locally gives developers immediate feedback, while CI/CD provides an additional validation layer before changes are merged.&lt;/p&gt;

&lt;p&gt;Read the full article on &lt;a href="https://github.com/30Piraten/technical-articles/blob/main/docs/openapi-and-schema-design.md" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>openai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>devops</category>
    </item>
    <item>
      <title>The Journey of a Network Packet: A TCP/IP Guide</title>
      <dc:creator>REV</dc:creator>
      <pubDate>Thu, 23 May 2024 20:55:34 +0000</pubDate>
      <link>https://dev.to/3rev/demystifying-tcpip-understanding-the-journey-of-a-network-packet-38g7</link>
      <guid>https://dev.to/3rev/demystifying-tcpip-understanding-the-journey-of-a-network-packet-38g7</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Prerequisite&lt;/li&gt;
&lt;li&gt;
The TCP/IP Model

&lt;ul&gt;
&lt;li&gt;Computer Networking in Today's Digital Landscape&lt;/li&gt;
&lt;li&gt;The significance of Networking to End-Users&lt;/li&gt;
&lt;li&gt;Benefits of the TCP/IP Model&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Understanding the TCP/IP Model

&lt;ul&gt;
&lt;li&gt;The Link Layer&lt;/li&gt;
&lt;li&gt;The Network Layer&lt;/li&gt;
&lt;li&gt;The Transport Layer&lt;/li&gt;
&lt;li&gt;The Application Layer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Functions of the TCP/IP Model&lt;/li&gt;
&lt;li&gt;
Understanding Packets

&lt;ul&gt;
&lt;li&gt;What is in a packet header&lt;/li&gt;
&lt;li&gt;Common types of Network Packets&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The Journey of a Packet&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The internet works through the seamless transmission of packets. Packets are the basic&amp;nbsp;unit of data exchange. This article provides an overview of the journey of a packet across the&amp;nbsp;TCP/IP model. Elucidating its critical role in networking.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;Basic understanding of &lt;a href="https://www.ibm.com/topics/networking" rel="noopener noreferrer"&gt;Computer networks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Familiarity with the &lt;a href="https://aws.amazon.com/what-is/osi-model/" rel="noopener noreferrer"&gt;OSI model&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Basic knowledge of &lt;a href="https://www.geeksforgeeks.org/tcp-ip-in-computer-networking/" rel="noopener noreferrer"&gt;TCP/IP protocol suite&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Basic networking tools &lt;a href="https://www.wireshark.org/docs/wsug_html_chunked/" rel="noopener noreferrer"&gt;WireShark&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The TCP/IP Model
&lt;/h2&gt;

&lt;p&gt;Before we begin our journey, let us first&amp;nbsp;understand what Computer Networking is. Its relevance in IT operations, Cloud services, and the internet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Computer Networking in Today's Digital Landscape
&lt;/h3&gt;

&lt;p&gt;Computer networking involves transferring and exchanging data between interconnected computing devices or nodes over physical or wireless technologies, following a set of rules known as communication protocols. Computer networking enables devices and endpoints to connect on a local area network (LAN) or larger networks like the internet or private wide area networks (WANs). This connectivity is essential for service providers, businesses, and consumers worldwide to share resources, access services, and communicate. Networking supports a wide range of activities, from telephone calls and text messaging to streaming video and the &lt;a href="https://learn.microsoft.com/en-us/azure/iot/iot-introduction" rel="noopener noreferrer"&gt;Internet of Things.&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Cloud services and internet functionality enable seamless integration and communication between on-premises infrastructure and cloud platforms, facilitating data transfer, application deployment, and access to cloud-based resources. Networking provides the underlying infrastructure for cloud services such as &lt;a href="https://learn.microsoft.com/en-us/azure/virtual-network/virtual-networks-overview" rel="noopener noreferrer"&gt;virtual private clouds - VPCs&lt;/a&gt; load balancers, and content delivery networks (CDNs), ensuring reliable and scalable cloud solutions.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Significance of Networking to End-Users
&lt;/h3&gt;

&lt;p&gt;End-users should care about networking because it is essential for accessing shared resources, internet connectivity, and optimal application performance. Networking directly impacts productivity and efficiency by enabling seamless communication and collaboration. It also plays a crucial role in ensuring the security and privacy of data and protecting against unauthorized access and cyber threats. Moreover, staying informed about networking helps end-users leverage emerging technologies like cloud computing and IoT, enhancing their digital experience and personal or professional growth. &lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of the TCP/IP Model
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Global Adoption: The TCP/IP model is the foundation of internet communication, enabling seamless connectivity among devices across different vendors and platforms, thus promoting worldwide interconnectivity in the digital realm.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scalability and Adaptability: With its modular architecture the TCP/IP model effortlessly integrates new technologies and protocols, ensuring it can meet evolving networking needs and readily accommodate future advancements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cross-Platform Compatibility: The TCP/IP model facilitates smooth communication across diverse devices and platforms, allowing for data exchange between various protocols and technologies and enhancing connectivity in the digital landscape.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standardization of the Internet: As the standard for Internet communication, the TCP/IP model guides the development and implementation of networking protocols and technologies. With a unified framework, it promotes compatibility and consistency across networks.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Understanding The TCP/IP Model
&lt;/h2&gt;

&lt;p&gt;The TCP/IP model is a structure that outlines the protocols and standards governing data transmission across networks. It consists of four interlinked layers, each responsible for facilitating network communication. Named after its primary protocols, TCP guarantees dependable data delivery, while IP manages data packet routing and addressing. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Internet Model&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Application&lt;/td&gt;
&lt;td&gt;Bidirectional reliable byte stream between two applications, using application-specific semantics (HTTP, BitTorrent)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transport&lt;/td&gt;
&lt;td&gt;Guarantees correct, in-order end-to-end delivery of data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network&lt;/td&gt;
&lt;td&gt;Delivers datagram end-to-end. Best effort delivery - with no guarantees. Must use the Internet Protocol (IP)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Link&lt;/td&gt;
&lt;td&gt;Delivers data over a single link between an end host and router or between routers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At the top of the TCP/IP model is the Application layer, with applications like BitTorrent and WorldWideWeb, which communicate to its peer layer. When the application has data to transmit, it sends it to the transport layer, whose job is to deliver the data reliably or otherwise to the destination. The transport layer then forwards this data to the network layer responsible for segmenting the data into packets, each tagged with the correct destination and address. Subsequently, the link layer receives the packet, which ensures its delivery from one node to the next along its path. The data progresses hop by hop through routers until it reaches the destination. All four layers facilitate reliable communication between applications in the end hosts. Each layer has a different responsibility, with higher layers building upon those beneath them, culminating in a bidirectional, reliable byte stream communication between applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Link Layer
&lt;/h3&gt;

&lt;p&gt;The link layer is the foundation of the TCP/IP protocol model, functioning as the interface between the network hardware and the rest of the network stack. Its primary role is to facilitate the transmission and reception of data across the physical network, providing a means for devices to communicate within the local area network (LAN). &lt;/p&gt;

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5vq3zlukjghkflca94pk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5vq3zlukjghkflca94pk.png" alt="Packets movement, hop-by-hop over each link" width="626" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The key responsibilities of the link layer include managing communication with the network adapter, coordinating data transmission according to the appropriate access method (Ethernet, token ring), formatting data into frames for transmission, handling errors in incoming frames, and acknowledging receipt of data frames while ensuring reliable delivery. Additionally, the link layer assigns addresses to network interface devices, which allows communication with devices on other networks.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Network Layer
&lt;/h3&gt;

&lt;p&gt;The network layer's primary function is to ensure the end-to-end delivery of packets across the internet - from the source and reaching the destination. Packets serve as a fundamental component in the network. They denote data accompanied by a header, its content, destination, and origin.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdveywhojasjigv41ekyz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdveywhojasjigv41ekyz.png" alt="A simple packet with data and a header." width="632" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Network layer packets are called datagrams. They include the data and a header containing the - to and from  - addresses. The network layer hands the datagram to the link layer, telling it to send it to the first link. The link layer says if you give me a datagram to send, I will transmit it over one link for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fui7r4ohtzu2dv1xvvqe9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fui7r4ohtzu2dv1xvvqe9.png" alt="Transmission of packets from the Source End host to a router." width="720" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the other end of the link is a &lt;em&gt;router&lt;/em&gt;. The link layer of the router accepts the datagram from the link and hands it up to the network layer inside the router. The network layer on the router examines the destination address of the datagram. It then routes the datagram, one hop at a time, to its eventual destination. And it does this by sending it to the link layer again. To carry it over to the next link, which is passed to the network layer on the next router and so on, until it reaches the network layer of its destination.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmsj46b893tppnsx0831l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmsj46b893tppnsx0831l.png" alt="Movement of packets from the Source End host to the Destination End host." width="720" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The network layer does not need to concern itself with how the link layer sends the datagram over each link. This separation of concerns between the network and link layers allows each to focus on its job without worrying about how the other layer works. It also means that a single network layer has a common way of talking to many link layers by simply handling the datagrams to send. The modularity of each layer makes this separation of concerns possible, coupled with a well-defined API to the layer below.&lt;/p&gt;

&lt;p&gt;When we send packets to the internet, we must use the internet protocol (IP). It is the IP that holds the internet together. The IP strives to deliver datagrams to their intended destinations. But it does not guarantee successful delivery. Datagrams can be lost, delivered out of sequence, or not delivered. Despite these potential issues, the internet can still function effectively. Applications often require another protocol layered on the IP to ensure reliable data delivery. This protocol operates at the &lt;em&gt;transport layer&lt;/em&gt;  and its responsibility is managing end-to-end communication between applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Transport Layer
&lt;/h3&gt;

&lt;p&gt;The Transmission Control Protocol — TCP — is the most common Transport layer. The TCP’s job is to guarantee that the data sent by an application at one end of the internet is delivered correctly to the application at the other end. If the network layer drops some datagrams, the TCP will transmit them multiple times if needed. If the network layer delivers them out of order — perhaps if two packets follow a different path to their destination. TCP will put the data back into the correct order again.&lt;/p&gt;

&lt;p&gt;TCP provides applications with a service that ensures that data is delivered correctly and in the intended order - despite the unreliable nature of the underlying network layer's datagram delivery service. This means that TCP guarantees the correct sequencing and delivery of data packets, addressing issues like packet loss, out-of-order delivery, and duplication. Applications like web and email clients greatly benefit from TCP's reliability because it allows them to focus on their core functionalities without complex internal error-handling mechanisms. By relying on TCP, these applications can delegate the responsibility of reliable data transfer, thus abstracting away the complexities of network communication and ensuring seamless and dependable data transmission.&lt;/p&gt;

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

&lt;p&gt;However, not every service requires a reliable delivery of data packets. Consider a scenario of a video snippet transmission via packets during a WhatsApp call. If there is a network latency, multiple re-transmissions of packets may not be essential. Opting to forego re-transmission could be the optimal choice. &lt;a href="https://www.freecodecamp.org/news/tcp-vs-udp/" rel="noopener noreferrer"&gt;UDP: User Datagram Protocol&lt;/a&gt; can be used for applications that do not need a reliable delivery service.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Application Layer
&lt;/h3&gt;

&lt;p&gt;The application layer is at the top of the TCP/IP model, and it defines TCP/IP application protocols and facilitates the interface between host programs and Transport layer services for network usage. The Application layer includes several high-level services such as DNS (Domain Naming System), HTTP (Hypertext Transfer Protocol), Telnet, SSH, etc.&lt;/p&gt;

&lt;p&gt;Every application interacts with the transport layer through a well-defined API, originating from the application layer to access the underlying TCP or UDP service. Applications mostly want a &lt;a href="https://book.systemsapproach.org/e2e/tcp.html" rel="noopener noreferrer"&gt;bidirectional reliable byte stream&lt;/a&gt; between endpoints, using their protocols to define the syntax of data exchange.&lt;/p&gt;

&lt;p&gt;For example, when a web client sends a GET request to a web server, it sends the request as an ASCII string along with the URL. From the application layer's viewpoint, the request is sent straight to its peer at the receiving end (the web server application) without knowing the underlying transmission configurations. The application layer delegates the GET request to the TCP layer for accurate delivery, which in turn utilizes the services of the network layer and relies on the link layer for transmission.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functions of the TCP/IP Model
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Logical Addressing:&lt;br&gt;
TCP/IP implements logical addressing to accommodate numerous hosts across diverse networks. IP manages this mechanism, ensuring data packets reach the appropriate networks and nodes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;IP Manages Routing:&lt;br&gt;
Handling the critical task of routing data packets, IP determines the next node along the transmission path from source to destination. This ensures that data packets reach their intended destinations, even if the sender is unaware of the specific location.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;TCP Ensures Error and Flow Control:&lt;br&gt;
Establishing a virtual connection between senders and receivers, TCP maintains continuous communication and incorporates error and flow control mechanisms. Enabling reliable data transfer and ensures connection stability throughout the transmission process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;TCP Supports Applications:&lt;br&gt;
TCP assigns unique TCP and UDP ports to applications, which allows for the seamless differentiation of specific applications and their communication link.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Understanding Packets
&lt;/h2&gt;

&lt;p&gt;A packet consists of the data intended for delivery and a header containing information about its destination and origin within the network. When a user requests to load an image, the image file is not transmitted from the web server to the user's computer as a single entity. Instead, the image is broken into bits of packets, transmitted across the internet via cables, and then reassembled by the user's computer to reconstruct the original image.&lt;/p&gt;

&lt;p&gt;The efficiency, reliability, scalability, and flexibility make packets vital in internet communication. Breaking data into smaller packets or sizes optimizes network resources, while error detection and correction mechanisms enhance reliability. The internet employs &lt;a href="https://en.wikipedia.org/wiki/Packet_switching" rel="noopener noreferrer"&gt;packet switching&lt;/a&gt;. Packet switching divides data into smaller packets for efficient transmission between computers. This approach enhances network performance by allowing multiple connections in parallel over the same wires and enabling networking equipment to process packets independently. Packet switching also enhances network resilience and efficiency by permitting packets to take various paths to their destination, encouraging data exchange among billions of devices.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is in a packet header?
&lt;/h3&gt;

&lt;p&gt;Examining the IPv4 packet header, we can see what travels with a packet to its destination. &lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Bit 0: Typically refers to the first bit in a bit sequence. In networking, the order in bits transfer can depend on the network protocol used. For instance, Ethernet and IP do not specifically define the order in which individual bits travel on the wire, but rather the order of bytes and fields.&lt;/li&gt;
&lt;li&gt;IPv4 Header: Contains several critical fields for routing and handling packets. The most important fields include:

&lt;ul&gt;
&lt;li&gt;Destination IP Address: Indicates the packet's intended recipient.&lt;/li&gt;
&lt;li&gt;Source IP Address: Indicates the packet's origin.&lt;/li&gt;
&lt;li&gt;Protocol ID: Specifies the higher-level protocol used in the data field (e.g., TCP, UDP). This field helps the destination host &lt;a href="https://www.prepbytes.com/blog/computer-network/multiplexing-and-demultiplexing-in-transport-layer/" rel="noopener noreferrer"&gt;demultiplex&lt;/a&gt; arriving data, routing it to the appropriate protocol handler. For example, a Protocol ID value of 6 indicates that the data contains a TCP segment and is thus passed to the TCP processing module.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The Internet Assigned Numbers Authority (IANA) defines over &lt;a href="https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml" rel="noopener noreferrer"&gt;140 different protocol numbers&lt;/a&gt; representing various transport and network layer protocols.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Version: This 4-bit field specifies the IP version in use. The values are 4 for IPv4 and 6 for IPv6. The header described here is for IPv4.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Total Length: This 16-bit field specifies the entire packet size - including the header and data in bytes. The maximum size is 65,535 bytes (64 KB).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Time to Live (TTL): This 8-bit field prevents packets from circulating indefinitely. Each router that forwards the packet decrements the TTL by 1. TTL discards the packet when it reaches zero. This mechanism ensures packets do not loop forever.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Packet Identification: This 16-bit field identifies the fragments of an original IP packet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Flags: This 3-bit field controls and identifies fragments. The most significant bit is reserved. The remaining two bits are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DF (Don't Fragment): The packet cannot be fragmented.&lt;/li&gt;
&lt;li&gt;MF (More Fragments): Indicates more fragments. If not set, it indicates the last fragment.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fragment Offset: This 13-bit field specifies the position of fragments in the original packet, measured in 8-byte blocks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Type of Service (ToS): This field indicates the quality of service desired for the packet. Routers can use the ToS to prioritize packets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Header Length: This 4-bit field indicates the length of the IP header in 32-bit words. The minimum value is 5 (20 bytes), and the maximum is 15 (60 bytes), accommodating optional fields.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Header Checksum: This 16-bit field checks the header's integrity. It ensures the header is uncorrupted in transit. The header rejects the packet if the checksum does not match the calculated value. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Common Types of Network Packets
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Packet Type&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Data Packets&lt;/td&gt;
&lt;td&gt;Transport user data or application-specific information&lt;/td&gt;
&lt;td&gt;Segments of emails or file downloads&lt;/td&gt;
&lt;td&gt;Encapsulate user data and ensure delivery from source to destination&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Control Packets&lt;/td&gt;
&lt;td&gt;Manage and control network communications&lt;/td&gt;
&lt;td&gt;TCP control packets like SYN, SYN-ACK, and ACK&lt;/td&gt;
&lt;td&gt;Facilitate establishment, maintenance, and termination of network sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Routing Packets&lt;/td&gt;
&lt;td&gt;Inform routers about network topology changes and determine the best path&lt;/td&gt;
&lt;td&gt;OSPF and BGP packets&lt;/td&gt;
&lt;td&gt;Maintain and update routing tables to ensure data takes the most efficient path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fragmentation Packets&lt;/td&gt;
&lt;td&gt;Divide large data packets into smaller fragments to accommodate MTU&lt;/td&gt;
&lt;td&gt;IP fragmentation packets&lt;/td&gt;
&lt;td&gt;Allows the transmission of large packets over networks with smaller MTU sizes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Acknowledgement Packets&lt;/td&gt;
&lt;td&gt;Confirm successful receipt of data packets&lt;/td&gt;
&lt;td&gt;TCP ACK packets&lt;/td&gt;
&lt;td&gt;Provide feedback to the sender upon receiving data correctly, ensuring reliable transmission&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Broadcast Packets&lt;/td&gt;
&lt;td&gt;Simultaneously send data to all nodes in a local network segment&lt;/td&gt;
&lt;td&gt;ARP requests&lt;/td&gt;
&lt;td&gt;Enable network-wide communication for tasks like address resolution and network discovery&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Journey of a Packet
&lt;/h2&gt;

&lt;p&gt;The TCP/IP Model picks up a stream of data from the application layer, and the transport layer breaks the stream into a segment of data that it reliably delivers to an application running on another computer. The transport layer sends these segments as network layer packets - which the network layer delivers to other computers. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;application [streams of data] -&amp;gt; transport [breaks the stream of data into segments] -&amp;gt; network [sends network layer packets to other computers].&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljbljnagj3v6l3fu1b6k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljbljnagj3v6l3fu1b6k.png" alt="The Transmission Control Protocol Byte Stream" width="720" height="295"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Almost all web traffic is over TCP. Its typical operation is between a client and a server. To open a connection a client sends a connection request, which the server responds to. This exchange takes three messages, called the three-way handshake.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The first step of the message is when the client sends a Synchronize message to the server, often called the SYN.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The second step is when the server responds with a synchronized message. Acknowledging the client Synchronize or a Synchronize / Acknowledge message - called a SYN/ACK.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The third and final step is when the client responds by acknowledging the server Synchronize, called an ACK.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;From the network layer point of view, packets sent to different applications on the same computer look the same. Hence, we need two addresses to open a TCP stream to another program. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first is the IP address: the address of the network layer.&lt;/li&gt;
&lt;li&gt;The second is a TCP port: this tells the computer software which application to deliver.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Web servers usually run on TCP Port 80. So when we open a connection to a web server, we send IP packets to the computer's IP address. Those IP packets have TCP segments whose destination port is 80.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But how does an IP Packet get to its destination&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Given that a direct physical link between a client (say, A) and a server may not exist. Client A often connects to an intermediary, typically a router. This router, in turn, establishes connections with other routers in the network. The journey of IP packets from client A to the server involves multiple stages, known as hops, where each hop represents a connection between two routers. If client A accesses the network via Wi-Fi, the hop involves wireless communication to reach the network access point. Conversely, if client A employs a wired connection like Ethernet, the data transmission traverses physical cables, eliminating the need for wireless hops.&lt;/p&gt;

&lt;p&gt;A wired connection from the access point leads to the broader internet. The router forwards client A packet along this wired hop. A router can have many links connecting to it. Upon the arrival of each packet, the router determines the appropriate outbound link for transmission. Routers possess IP addresses, which may lead to delivering a packet to its corresponding software and not forwarding it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inside the stream&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Inside each hop&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;For example, IP packets are forwarded to the router IP address when you log in to a router using TCP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does a router make this decision&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The router achieves this through a forwarding table. It comprises IP address patterns and their associated outbound links. When a packet arrives, it assesses which entry in the forwarding table best matches its pattern and directs the packet through the link specified in that entry. Typically, the term &lt;em&gt;best&lt;/em&gt; signifies the most specific match.&lt;/p&gt;

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

&lt;p&gt;The &lt;em&gt;default&lt;/em&gt; route is the least specific. It matches every IP address. If a packet arrives and there is nothing but the default one, the router will use the &lt;em&gt;default&lt;/em&gt; route.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In computer networking, packets follow the TCP/IP Model. It begins at the application layer when an app wants to send data. The transport layer, with protocols like TCP and UDP, deals with splitting data, controlling the flow, and finding errors. The packet gets wrapped in an IP header that guides it across the internet at the network layer. Lastly, the link layer ensures the packet goes over the physical network. When the packet reaches its destination, it reverses the steps. It begins at the link layer, where it is received and decoded. The network layer looks at the IP header to discern where the packet should go. The transport layer checks the data for problems and puts it in order if needed. Finally, the Application layer hands the data to the receiving app. Along the way, packets are handled to ensure they go from the source to the destination.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>webdev</category>
      <category>programming</category>
      <category>computerscience</category>
    </item>
  </channel>
</rss>
