DEV Community

Ali Aygör
Ali Aygör

Posted on Fully Autonomous

6 debugging checks for JSON, JWT, SQL, regex, timestamps and URLs

An API failure is often easier to investigate when you separate six questions: what did the response contain, what does the token prove, which date are you reading, what does the query actually return, what does the pattern match, and what will the generated request send?

The examples below are synthetic. You can reproduce them locally without an account, a real credential or a running API.

1. Valid JSON can still have the wrong shape

The first response below is an object. The second is a JSON string containing the serialized representation of an object. Both are valid JSON.

const objectText = JSON.stringify({ ok: true });
const wrappedText = JSON.stringify(objectText);

const objectValue = JSON.parse(objectText);
const stringValue = JSON.parse(wrappedText);

console.log(typeof objectValue); // object
console.log(typeof stringValue); // string
console.log(stringValue.ok);     // undefined
Enter fullscreen mode Exit fullscreen mode

Formatting checks readability; syntax validation checks whether the text parses; schema validation checks the resulting value against a contract. Those are different operations.

If your client expects an object, confirm that it is neither null nor an array. Parse a second time only if the API contract specifies an encoded string. Removing every backslash is not a reliable repair: backslashes can be legitimate string content.

2. A decoded JWT is evidence, not authentication

Reading JWT claims does not verify the signature, issuer, audience or authorization rules. Even an unexpired token can be forged, intended for another service or revoked.

JWT NumericDate values use seconds. JavaScript dates use milliseconds:

const claims = { aud: ["api", "reports"], exp: 1700000000 };
console.log(new Date(claims.exp * 1000).toISOString());
// 2023-11-14T22:13:20.000Z
Enter fullscreen mode Exit fullscreen mode

The audience can also be an array. A decoder that assumes every aud value is a string can misrepresent an otherwise legitimate claim set.

Use a synthetic token for inspection. Your server must verify the token with its trusted keys and configured validation rules. A browser decoder should never label a token authentic just because its payload is readable.

3. A timestamp can be correct and still be interpreted incorrectly

If an event appears in 1970, first check the unit before changing a timezone setting.

console.log(new Date(1700000000).toISOString());
// 1970-01-20T16:13:20.000Z: interpreted as milliseconds

console.log(new Date(1700000000 * 1000).toISOString());
// 2023-11-14T22:13:20.000Z: seconds converted to milliseconds
Enter fullscreen mode Exit fullscreen mode

Keep the original value, its documented unit and the UTC representation together. Digit count is a useful hint, not a universal contract. Local-time displays also depend on the viewer's timezone, so compare UTC values when connecting events from different systems.

4. Pretty SQL can reveal an unintended join

Consider a report intended to retain every customer and attach a pending order when present:

SELECT c.id, o.id
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.status = 'pending';
Enter fullscreen mode Exit fullscreen mode

For an unmatched customer, o.status is null. The WHERE predicate therefore removes that customer. If you intend to retain every customer while matching only pending orders, move that condition into the join:

SELECT c.id, o.id
FROM customers c
LEFT JOIN orders o
  ON o.customer_id = c.id
 AND o.status = 'pending';
Enter fullscreen mode Exit fullscreen mode

These queries express different results. Test a customer with no orders, one with only a completed order, and one with a pending order. Formatting helps expose the distinction; it cannot certify performance. Use the database's execution plan with representative data for that separate question.

5. Regex flags change the answer

Testing one positive example can hide an anchoring or flag problem. Start with multiple matches and a counterexample:

const text = "ORDER-123 noop ORDER-456 ORDER-ABC";
console.log(text.match(/ORDER-\d+/));
// first match: ORDER-123
console.log(text.match(/ORDER-\d+/g));
// ["ORDER-123", "ORDER-456"]
console.log(/^ORDER-\d+$/.test("prefix ORDER-123"));
// false: whole-string validation
Enter fullscreen mode Exit fullscreen mode

JavaScript and other regex engines do not support exactly the same syntax. Check the target engine and escaping rules before copying a pattern into another language. Expensive expressions can also stall a browser tab; a worker with an execution limit is useful for a tester, but not a substitute for reviewing production patterns.

6. Query decoding must preserve repeated values

An encoded plus sign and a literal plus sign are not interchangeable in form-style query parsing. Repeated parameters also matter:

const url = new URL("https://example.com/search?tag=api&tag=java&q=C%2B%2B#section");
console.log(url.searchParams.getAll("tag")); // ["api", "java"]
console.log(url.searchParams.get("q"));      // C++
console.log(new URLSearchParams("q=C++").get("q")); // C followed by two spaces
Enter fullscreen mode Exit fullscreen mode

The fragment is not part of the query sent to the server. When rebuilding a request, preserve repeated values unless the API explicitly requires a single value. Converting the parameters straight into a plain object can discard duplicates.

Keep a small investigation record

For each check, retain the redacted input, expected result, actual result, selected options and environment. That makes the observation reproducible rather than dependent on whichever tool happens to look convincing.

For copyable inputs with expected outputs, use the synthetic fixture pack. It also includes Base64 decoding and a local check script. The unsigned JWT is an expired inspection example, not an authentication credential.

Disclosure: I maintain Developer Debug Tools, a free collection covering these workflows plus SQL formatting, request generation, JSON Schema, Java stacktraces and OpenAPI comparison. Core tool processing runs in the browser; hosting and optional analytics/advertising are separate services.

This article was prepared with AI assistance; its JavaScript examples and SQL join fixture were checked locally.

References: JSON specification, JWT specification, PostgreSQL join semantics, JavaScript match, URLSearchParams.

Top comments (0)