<?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: Kuruba Ramesh</title>
    <description>The latest articles on DEV Community by Kuruba Ramesh (@krameshr).</description>
    <link>https://dev.to/krameshr</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3981848%2F7a8f30d7-1044-4f8c-9275-09e699536538.png</url>
      <title>DEV Community: Kuruba Ramesh</title>
      <link>https://dev.to/krameshr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/krameshr"/>
    <language>en</language>
    <item>
      <title>How I Integrated Specmatic Contract Testing into a Real Banking API (ValueMeters)</title>
      <dc:creator>Kuruba Ramesh</dc:creator>
      <pubDate>Fri, 12 Jun 2026 19:37:56 +0000</pubDate>
      <link>https://dev.to/krameshr/how-i-integrated-specmatic-contract-testing-into-a-real-banking-api-valuemeters-cak</link>
      <guid>https://dev.to/krameshr/how-i-integrated-specmatic-contract-testing-into-a-real-banking-api-valuemeters-cak</guid>
      <description>&lt;h2&gt;
  
  
  My Background
&lt;/h2&gt;

&lt;p&gt;I am K. Ramesh, a Full Stack Developer from India specialising in the MERN stack and Java Spring Boot. I recently completed my Executive PG Certification in Full Stack Web Development from IIT Roorkee and I am currently building my portfolio to crack my first developer job.&lt;/p&gt;

&lt;p&gt;As part of the &lt;strong&gt;Specmatic Full Stack AI Engineering Internship&lt;/strong&gt; assessment, I was asked to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Complete the Specademy course on Spec-First Engineering&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%2F6k4rouudyq4tbweretz5.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%2F6k4rouudyq4tbweretz5.png" alt=" " width="540" height="387"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Integrate Specmatic into a real project&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write about what I built and what I learnt&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This blog post is my honest account of that journey — the struggles, the breakthroughs, and the real learnings.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Specmatic? Why Should You Care?
&lt;/h2&gt;

&lt;p&gt;Before I started the Specademy course, I had never heard of contract testing. I knew about unit testing and integration testing, but contract testing was completely new to me.&lt;/p&gt;

&lt;p&gt;After completing the course, one analogy stuck with me permanently:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Contract testing is compiler safety for API calls.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let me explain this with a simple example.&lt;/p&gt;

&lt;p&gt;In a traditional monolithic application, if Service A calls a function in Service B with the wrong parameters, the &lt;strong&gt;compiler immediately catches it&lt;/strong&gt; and refuses to build. You cannot even run the app with a type mismatch.&lt;/p&gt;

&lt;p&gt;But in microservices, Service A and Service B talk over HTTP. They are separate applications, often written in different programming languages. When Service A sends a request to Service B with the wrong schema — maybe a field name changed, maybe a data type changed — &lt;strong&gt;no compiler catches it&lt;/strong&gt;. It only fails at runtime, often in production, causing real damage.&lt;/p&gt;

&lt;p&gt;This is what Specmatic solves. It reads your &lt;strong&gt;OpenAPI specification&lt;/strong&gt; and uses it as an executable contract. It fires test requests at your API and checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does the response match the documented schema?&lt;/li&gt;
&lt;li&gt;Are the HTTP status codes correct?&lt;/li&gt;
&lt;li&gt;Are the response headers correct?&lt;/li&gt;
&lt;li&gt;Are all documented endpoints actually implemented?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If anything breaks the contract, the test fails — just like a compiler error.&lt;/p&gt;




&lt;h2&gt;
  
  
  About My Project: ValueMeters
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ValueMeters&lt;/strong&gt; is an online banking system I built from scratch. It is a full-stack application with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Java Spring Boot with JWT authentication, MySQL database, Spring Data JPA&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; React 18 with Vite and Tailwind CSS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment:&lt;/strong&gt; Backend on Railway/Render, Frontend on Vercel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Documentation:&lt;/strong&gt; springdoc-openapi (auto-generates OpenAPI spec at &lt;code&gt;/v3/api-docs&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application has &lt;strong&gt;13 REST API endpoints&lt;/strong&gt; across 5 controllers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Controller&lt;/th&gt;
&lt;th&gt;Endpoints&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AuthController&lt;/td&gt;
&lt;td&gt;POST /auth/register, POST /auth/login&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AccountController&lt;/td&gt;
&lt;td&gt;GET /account/user/{userId}, GET /account/{accountNumber}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TransactionController&lt;/td&gt;
&lt;td&gt;POST /transaction/deposit/{accountId}, POST /transaction/withdraw/{accountId}, POST /transaction/transfer/{fromAccountId}, GET /transaction/history/{accountId}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ExpenseController&lt;/td&gt;
&lt;td&gt;POST /expense/add/{accountId}, GET /expense/list/{accountId}, GET /expense/summary/{accountId}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BudgetController&lt;/td&gt;
&lt;td&gt;POST /budget/set/{accountId}, GET /budget/get/{accountId}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Since I already had &lt;code&gt;springdoc-openapi&lt;/code&gt; integrated, my OpenAPI spec was available at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:8080/v3/api-docs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This made ValueMeters a perfect candidate for Specmatic integration.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Challenge: JWT Security Was Blocking Specmatic
&lt;/h2&gt;

&lt;p&gt;The biggest challenge I faced was that ValueMeters uses &lt;strong&gt;JWT authentication&lt;/strong&gt;. Every endpoint (except register and login) requires a valid JWT token in the &lt;code&gt;Authorization&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;When Specmatic tries to hit these endpoints during contract testing, it sends requests without any token. Spring Security was returning &lt;strong&gt;403 Forbidden&lt;/strong&gt; before Specmatic could even read the OpenAPI spec.&lt;/p&gt;

&lt;p&gt;I had to solve this without breaking the production security setup. I did not want to hardcode any test bypasses into the main codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution: Spring Profiles
&lt;/h3&gt;

&lt;p&gt;I used &lt;strong&gt;Spring's profile system&lt;/strong&gt; to create a completely separate security configuration for testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Added &lt;code&gt;@Profile("!test")&lt;/code&gt; to the existing &lt;code&gt;SecurityConfig.java&lt;/code&gt; so it only loads when the test profile is NOT active:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@EnableWebSecurity&lt;/span&gt;
&lt;span class="nd"&gt;@Profile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"!test"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Does not load during tests&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SecurityConfig&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... existing JWT security configuration&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Created a new &lt;code&gt;TestSecurityConfig.java&lt;/code&gt; that only loads during tests and permits all requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@Profile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Only loads during tests&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestSecurityConfig&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SecurityFilterChain&lt;/span&gt; &lt;span class="nf"&gt;testFilterChain&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpSecurity&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;securityMatcher&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/**"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;csrf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csrf&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;csrf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;disable&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cors&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cors&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;disable&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authorizeHttpRequests&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;anyRequest&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;permitAll&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;httpBasic&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;basic&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;basic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;disable&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;formLogin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;disable&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Created &lt;code&gt;src/test/resources/application-test.properties&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;spring.autoconfigure.exclude&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration&lt;/span&gt;
&lt;span class="py"&gt;spring.profiles.active&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;test&lt;/span&gt;
&lt;span class="py"&gt;springdoc.api-docs.enabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach keeps production security &lt;strong&gt;completely untouched&lt;/strong&gt; while giving Specmatic full access during testing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting Up Specmatic
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Added Maven Dependency
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.specmatic&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;junit5-support&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.0.18&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Created specmatic.yaml in Project Root
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;web"&lt;/span&gt;
    &lt;span class="na"&gt;test&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;http://localhost:8080/v3/api-docs"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Specmatic to fetch the OpenAPI specification from the live application during testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Created the Contract Test Class
&lt;/h3&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%2Ffidl5jpfa6k6x902wyjy.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%2Ffidl5jpfa6k6x902wyjy.png" alt=" " width="800" height="423"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.banking&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.boot.test.context.SpringBootTest&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.test.context.ActiveProfiles&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.specmatic.test.SpecmaticJUnitSupport&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@SpringBootTest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;webEnvironment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SpringBootTest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;WebEnvironment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DEFINED_PORT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;properties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"server.port=8080"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@ActiveProfiles&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BankingContractTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;SpecmaticJUnitSupport&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"host"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"localhost"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"port"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"8080"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"endpointsAPI"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"http://localhost:8080/v3/api-docs"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;contractTest&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contractTest&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When this test runs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Spring Boot starts the full application on port 8080 with the test profile&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TestSecurityConfig&lt;/code&gt; loads instead of &lt;code&gt;SecurityConfig&lt;/code&gt; — all endpoints are open&lt;/li&gt;
&lt;li&gt;Specmatic fetches the OpenAPI spec from &lt;code&gt;/v3/api-docs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Specmatic automatically generates test scenarios for all 13 endpoints&lt;/li&gt;
&lt;li&gt;It fires requests and validates responses against the contract&lt;/li&gt;
&lt;li&gt;It generates an HTML coverage report&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Results and What They Mean
&lt;/h2&gt;

&lt;h3&gt;
  
  
  API Coverage Report
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|-----------------------------------------------------------------------------------------------------|
| SPECMATIC API COVERAGE SUMMARY                                                                      |
|-----------------------------------------------------------------------------------------------------|
| coverage | path                                  | method | response | result          |
|----------|---------------------------------------|--------|----------|-----------------|
| 50%      | /account/user/{userId}                | GET    | 200      | not implemented |
|          |                                       |        | 400      | missing in spec |
| 50%      | /account/{accountNumber}              | GET    | 200      | not implemented |
|          |                                       |        | 400      | missing in spec |
| 50%      | /auth/login                           | POST   | 200      | not implemented |
|          |                                       |        | 400      | missing in spec |
| 50%      | /auth/register                        | POST   | 200      | not implemented |
|          |                                       |        | 400      | missing in spec |
| 100%     | /expense/list/{accountId}             | GET    | 200      | not implemented |
| 100%     | /transaction/history/{accountId}      | GET    | 200      | not implemented |
|-----------------------------------------------------------------------------------------------------|
| 56% API Coverage reported from 13 Paths                                                             |
|-----------------------------------------------------------------------------------------------------|

Tests run: 20, Successes: 0, Failures: 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Flugjb0fc6fiwf9gv3ug2.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%2Flugjb0fc6fiwf9gv3ug2.png" alt=" " width="799" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding Why Tests Failed
&lt;/h3&gt;

&lt;p&gt;At first I was confused — all 20 tests failed? Did I do something wrong?&lt;/p&gt;

&lt;p&gt;Then I understood. These are &lt;strong&gt;not ordinary test failures&lt;/strong&gt;. These are &lt;strong&gt;contract gaps&lt;/strong&gt; — differences between what the API documentation promises and what the API actually delivers. Let me explain each finding:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finding 1: Missing 400 Error Responses in OpenAPI Spec&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Specmatic sent random test data (fake account IDs like &lt;code&gt;793&lt;/code&gt;, &lt;code&gt;283&lt;/code&gt;, &lt;code&gt;422&lt;/code&gt;) and received &lt;code&gt;400 Bad Request&lt;/code&gt; responses. But my OpenAPI spec only documented &lt;code&gt;200 OK&lt;/code&gt; responses for these endpoints.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expected status 200, actual was status 400
Reason: Account not found!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a &lt;strong&gt;real documentation bug&lt;/strong&gt;. My spec is incomplete — it does not tell consumers that these endpoints can fail with 400. Specmatic found it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finding 2: Content-Type Not Specified in Spec&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Contract expected */* but response contained application/json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some endpoints return &lt;code&gt;application/json&lt;/code&gt; but the OpenAPI spec did not explicitly declare the response content type. Another spec gap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finding 3: Schema Mismatch in Budget Summary&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Contract expected JSON object but response contained 0 (number)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;monthlySpent&lt;/code&gt; field in &lt;code&gt;/expense/summary&lt;/code&gt; returns a plain number (&lt;code&gt;0&lt;/code&gt;), but the OpenAPI spec described it as a JSON object. A genuine schema mismatch caught by Specmatic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The key insight:&lt;/strong&gt; These failures are &lt;strong&gt;findings, not errors&lt;/strong&gt;. Specmatic is doing exactly what a compiler does — it found real gaps between the contract and the implementation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Learnings From This Journey
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Your OpenAPI Spec is Probably Incomplete
&lt;/h3&gt;

&lt;p&gt;Before Specmatic, I thought my spec was fine because Swagger UI looked correct. After Specmatic, I realised my spec was missing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All 400/404 error response schemas&lt;/li&gt;
&lt;li&gt;Explicit Content-Type declarations&lt;/li&gt;
&lt;li&gt;Proper schema definitions for complex response objects&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Contract Testing Needs Zero Domain Knowledge
&lt;/h3&gt;

&lt;p&gt;As I learnt in the Specademy course, contract tests do not care about business logic. Specmatic does not know what a "bank account" is. It only checks HTTP semantics and JSON schema structure. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No test data setup required&lt;/li&gt;
&lt;li&gt;No understanding of business rules required&lt;/li&gt;
&lt;li&gt;Can be fully automated by AI agents&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Profile-Based Security is the Professional Approach
&lt;/h3&gt;

&lt;p&gt;Many developers (including me initially) think about disabling security globally for tests. The right approach is Spring profiles — keep production config untouched, create a separate test config. This is production-grade thinking.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The Integration Environment Problem is Real
&lt;/h3&gt;

&lt;p&gt;Before this exercise, I had read about the "integration environment bottleneck" in the Specademy course. After running Specmatic against a real project, I understood it practically. My API had 13 endpoints. Only 56% were properly documented. If another team was building a frontend against my API spec, they would have incorrect assumptions about 44% of the endpoints.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Specmatic as Compiler Safety for AI Agents
&lt;/h3&gt;

&lt;p&gt;The Specademy course mentioned that AI coding agents need reliable executable contracts to operate safely. After this exercise, I fully understand why. If an AI agent generates code that calls my &lt;code&gt;/expense/summary&lt;/code&gt; endpoint, it might assume the response has a &lt;code&gt;monthlySpent&lt;/code&gt; JSON object (as per spec). But the actual response has a plain number. The AI agent's code would crash. Specmatic prevents this by enforcing the contract.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Will Improve Next
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add 400/404 error response schemas&lt;/strong&gt; to all endpoints in the OpenAPI spec&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add realistic example data&lt;/strong&gt; to the spec so Specmatic generates meaningful test scenarios&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrate into GitHub Actions CI/CD&lt;/strong&gt; — run contract tests on every pull request&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explore Specmatic as a mock server&lt;/strong&gt; for the React frontend during development&lt;/li&gt;
&lt;/ol&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/KRameshr/valuemeters-specmatic" rel="noopener noreferrer"&gt;github.com/KRameshr/valuemeters-specmatic&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specmatic Integration Branch:&lt;/strong&gt; &lt;code&gt;main&lt;/code&gt; branch of the above repo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specademy Certificate:&lt;/strong&gt; Spec-First Engineering Course, completed 12 June 2026&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;When I started this assessment, I thought Specmatic would simply run some tests and show green ticks. Instead, it showed me 20 failures — and each failure was a real gap in my API documentation that I had never noticed before.&lt;/p&gt;

&lt;p&gt;That is the power of contract-driven development. It does not just test your code — it holds your API accountable to its promises.&lt;/p&gt;

&lt;p&gt;As the Specademy course taught: &lt;strong&gt;Contract testing is compiler safety for API calls.&lt;/strong&gt; After integrating Specmatic into ValueMeters, I truly understand what that means.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written by K. Ramesh — Full Stack Developer (MERN + Spring Boot), IIT Roorkee Executive PG Certification in Full Stack Web Development.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;LinkedIn: &lt;a href="https://linkedin.com/in/kurubaramesh" rel="noopener noreferrer"&gt;linkedin.com/in/kurubaramesh&lt;/a&gt;*26.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>specmatic</category>
      <category>java</category>
      <category>springboot</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
