<?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: Nusaik_Ahamath</title>
    <description>The latest articles on DEV Community by Nusaik_Ahamath (@nusaikaj).</description>
    <link>https://dev.to/nusaikaj</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%2F4192729%2F94b86e89-f57d-45ce-97de-3104e4c882c3.jpg</url>
      <title>DEV Community: Nusaik_Ahamath</title>
      <link>https://dev.to/nusaikaj</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nusaikaj"/>
    <language>en</language>
    <item>
      <title>APIWatch: Checking API Traffic and Subscription Controls with WSO2 API Manager</title>
      <dc:creator>Nusaik_Ahamath</dc:creator>
      <pubDate>Sun, 18 Oct 2026 19:23:30 +0000</pubDate>
      <link>https://dev.to/nusaikaj/apiwatch-checking-api-traffic-and-subscription-controls-with-wso2-api-manager-2797</link>
      <guid>https://dev.to/nusaikaj/apiwatch-checking-api-traffic-and-subscription-controls-with-wso2-api-manager-2797</guid>
      <description>&lt;p&gt;I recently worked on a project called APIWatch using Python and WSO2 API Manager. It is a small monitoring tool that reads API traffic logs and helps review errors, slow responses and unusual traffic.&lt;/p&gt;

&lt;p&gt;I ran the project on my laptop with a demo shop API. This post covers the setup, the problems I found and the results of my tests.&lt;/p&gt;

&lt;p&gt;One result is worth sharing early: the machine learning model did not improve detection in my controlled incident test. The simple checks used alongside it found all four test incidents.&lt;/p&gt;

&lt;h2&gt;
  
  
  What APIWatch does
&lt;/h2&gt;

&lt;p&gt;The demo shop has endpoints for products, orders and health checks. WSO2 API Manager sits in front of it. Requests go through WSO2 before reaching the Python backend.&lt;/p&gt;

&lt;p&gt;WSO2 handles API access and records gateway measurements. APIWatch reads those measurements and groups them into one-minute periods, called windows.&lt;/p&gt;

&lt;p&gt;For each window, APIWatch looks at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The number of requests.&lt;/li&gt;
&lt;li&gt;The share of requests that returned selected client errors, server errors or throttling responses.&lt;/li&gt;
&lt;li&gt;The average response time.&lt;/li&gt;
&lt;li&gt;The number of requests with a recorded response time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These values help show when traffic changes or the API starts having problems. The saved feature files leave out access tokens, usernames, client IP addresses and response bodies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting the local setup working
&lt;/h2&gt;

&lt;p&gt;One problem came from the Windows folder path. WSO2 failed to start when I placed it under &lt;code&gt;D:\MY PROJECTS&lt;/code&gt;. Moving the installation to &lt;code&gt;D:\Tools&lt;/code&gt; fixed that startup problem.&lt;/p&gt;

&lt;p&gt;After the gateway and backend were running, I called the products endpoint through WSO2. It returned HTTP 200 with the demo product list.&lt;/p&gt;

&lt;p&gt;I then checked the gateway metrics log. The request appeared there with its response status and timing. This confirmed that I could collect measurements from the running local gateway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Collecting normal traffic
&lt;/h2&gt;

&lt;p&gt;Before checking unusual traffic, I needed examples of normal traffic.&lt;/p&gt;

&lt;p&gt;A Python script sent successful GET requests at different rates. The first longer collection was planned for 55 minutes, but four one-minute windows were missing. I also left out an uncertain window just after that gap.&lt;/p&gt;

&lt;p&gt;After review, the training data contained &lt;strong&gt;50 one-minute windows and 2,491 requests&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I used these windows to train an Isolation Forest model. This model looks for patterns that differ from its training examples. Its score tells us how unusual a pattern looks; it does not tell us the chance that someone is attacking the API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Normal traffic also raised alerts
&lt;/h2&gt;

&lt;p&gt;In a later ten-minute normal session, the model flagged six windows.&lt;/p&gt;

&lt;p&gt;That was a useful problem to investigate. The requests were part of my scripted normal test, but the model still found some patterns unusual. Small changes in response time and combinations of values could fall outside the limited training examples. I did not have enough evidence to identify the physical cause of those changes.&lt;/p&gt;

&lt;p&gt;I used this session to calibrate how model scores turn into alerts. In simple terms, I compared new scores with scores from these normal examples. Once I used those ten windows to make that change, I could no longer use them as a fresh test.&lt;/p&gt;

&lt;p&gt;The updated policy also included checks called guards. These check for conditions such as many error responses, a high request rate or slow responses. For the slow-response check, I used a &lt;strong&gt;100 ms local lab budget&lt;/strong&gt;, with at least five recorded response times needed.&lt;/p&gt;

&lt;p&gt;That budget was a setting for this experiment. A different API would need its own response-time target.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing with fresh normal traffic
&lt;/h2&gt;

&lt;p&gt;I kept the detector settings fixed and collected another ten-minute normal session with a different traffic seed.&lt;/p&gt;

&lt;p&gt;This time, &lt;strong&gt;530 sent requests matched 530 gateway events&lt;/strong&gt;, with no missing windows. None of these windows had been used for calibration.&lt;/p&gt;

&lt;p&gt;The original ML model, calibrated ML model, hybrid method and original simple rules each raised &lt;strong&gt;one false alert out of ten normal windows&lt;/strong&gt;. The guards raised no alerts.&lt;/p&gt;

&lt;p&gt;So I could not claim that calibration improved the result. The earlier six false alerts and the later one false alert came from different sessions. The original model also produced one false alert in the fresh session.&lt;/p&gt;

&lt;p&gt;Ten windows are also too few to tell us how well the tool would work on production traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking errors, delays and traffic bursts
&lt;/h2&gt;

&lt;p&gt;Next, I ran a seven-minute controlled test. Each minute had one case:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ordinary successful requests.&lt;/li&gt;
&lt;li&gt;A legitimate traffic burst.&lt;/li&gt;
&lt;li&gt;Backend 404 responses.&lt;/li&gt;
&lt;li&gt;Backend 500 responses.&lt;/li&gt;
&lt;li&gt;Delayed responses.&lt;/li&gt;
&lt;li&gt;A request rate above the guard threshold.&lt;/li&gt;
&lt;li&gt;A return to ordinary traffic.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The demo backend has a lab mode for creating the error and delay cases. The test script checks its marked responses so a gateway login failure cannot be mistaken for an intended backend error.&lt;/p&gt;

&lt;p&gt;The run completed &lt;strong&gt;960 requests&lt;/strong&gt;, and all &lt;strong&gt;960 matched gateway events&lt;/strong&gt;. All seven test conditions were verified.&lt;/p&gt;

&lt;p&gt;There were four incident windows and three normal windows. Here are the results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Incidents found, out of 4&lt;/th&gt;
&lt;th&gt;Incidents missed&lt;/th&gt;
&lt;th&gt;False alerts, out of 3 normal windows&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Original ML&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Calibrated ML&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Guards only&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Calibrated hybrid&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Original simple rules&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The hybrid combines calibrated ML alerts with guard alerts. In this run, every hybrid alert came from a guard. The calibrated ML model added no detections.&lt;/p&gt;

&lt;p&gt;The legitimate burst reached &lt;strong&gt;147 requests per minute&lt;/strong&gt;. The hybrid accepted it, while the original simple rules raised a false alert.&lt;/p&gt;

&lt;p&gt;The excessive-rate case reached &lt;strong&gt;588 requests per minute&lt;/strong&gt;, above the fixed guard threshold of &lt;strong&gt;328 per minute&lt;/strong&gt;. The slow-response case had an average gateway response time of about &lt;strong&gt;304 ms&lt;/strong&gt;, which triggered the latency guard.&lt;/p&gt;

&lt;p&gt;The backend 404 and 500 cases triggered the matching error guards.&lt;/p&gt;

&lt;p&gt;These were deliberately created faults and traffic conditions. Finding all four proves that the expected checks worked in this short test. It does not establish general attack-detection accuracy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reviewing the results in a dashboard
&lt;/h2&gt;

&lt;p&gt;I also used a local dashboard to review the saved captures. It shows request rates, response times, alert reasons and comparisons between the methods.&lt;/p&gt;

&lt;p&gt;Each alert window can be marked as Confirmed incident, Benign or Investigate, with a note. The review is saved separately from the test labels and detector results.&lt;/p&gt;

&lt;p&gt;During my check, I reviewed all four pending alerts. The pending count became zero, while the four recorded alerts stayed visible.&lt;/p&gt;

&lt;p&gt;The dashboard currently reads saved files. It does not continuously collect and score live gateway traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blocking and restoring a subscription
&lt;/h2&gt;

&lt;p&gt;I ran a separate manual check using the APIWatchClient subscription in WSO2.&lt;/p&gt;

&lt;p&gt;I called GET &lt;code&gt;/apiwatchdemoshop/1.0.0/products&lt;/code&gt;, blocked the Production subscription in Publisher, tested again and then unblocked it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Before blocking&lt;/td&gt;
&lt;td&gt;HTTP 200 with the demo products&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;While blocked&lt;/td&gt;
&lt;td&gt;HTTP 401 with gateway code 900907&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;After unblocking&lt;/td&gt;
&lt;td&gt;HTTP 200 with the demo products again&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The error code mattered here. A 401 response alone can have different causes. WSO2 documents code &lt;strong&gt;900907&lt;/strong&gt; for a blocked subscription.&lt;/p&gt;

&lt;p&gt;I tested through the Developer Portal using fresh Production tokens after the changes. Gateway caching can affect existing tokens, so this check did not measure how quickly every previously issued token would be affected.&lt;/p&gt;

&lt;p&gt;I changed the subscription manually in WSO2 Publisher. The APIWatch dashboard did not perform the block. I also did not test Sandbox access or access from another application.&lt;/p&gt;

&lt;p&gt;I kept this check separate from the seven-window detector results.&lt;/p&gt;

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

&lt;p&gt;Getting a model to produce alerts was only one part of the work. I also had to check missing data, compare sent requests with gateway records, keep calibration data separate and test on fresh traffic.&lt;/p&gt;

&lt;p&gt;The most useful comparison was between the hybrid method and the guards alone. Both found the same four incidents in this run. Reporting that result gives a clearer picture of what the ML model contributed.&lt;/p&gt;

&lt;p&gt;APIWatch is still a local lab project. Further work could include longer tests, different traffic patterns and continuous collection. Automatic response actions would need separate implementation and testing.&lt;/p&gt;

&lt;p&gt;For now, the project shows a working WSO2 integration, traffic collection, detector comparisons, manual alert reviews and a checked subscription block-and-recovery flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;About AI assistance:&lt;/strong&gt; I used AI tools to help with coding and writing. I ran the WSO2 setup, traffic collection, dashboard reviews and subscription checks manually. The numbers in this post come from those saved lab results.&lt;/p&gt;

&lt;p&gt;Source code and setup guides: &lt;a href="https://github.com/nusaikaj/APIWatch" rel="noopener noreferrer"&gt;APIWatch on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://apim.docs.wso2.com/en/4.6.0/reference/troubleshooting/error-handling/" rel="noopener noreferrer"&gt;WSO2 API Manager error handling&lt;/a&gt; — reference for gateway code 900907.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apim.docs.wso2.com/en/4.5.0/manage-apis/design/advanced-topics/block-subscription-to-an-api/" rel="noopener noreferrer"&gt;WSO2 subscription blocking and unblocking&lt;/a&gt; — procedural reference, including token-cache considerations.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://scikit-learn.org/1.8/modules/generated/sklearn.ensemble.IsolationForest.html" rel="noopener noreferrer"&gt;scikit-learn IsolationForest documentation&lt;/a&gt; — reference for the model.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>api</category>
      <category>backend</category>
      <category>monitoring</category>
      <category>python</category>
    </item>
  </channel>
</rss>
