Skip to content

Commit 2ba9e08

Browse files
committed
docs(api): add creator query normalization docs with before/after examples (#211)
Adds docs/api/creator-query-normalization.md covering normalization rules for creatorId, creatorAddress, and username query params, with before/after tables and a link to the Zod validation layer. Links the doc from public-query-parse.utils.ts JSDoc comment. Closes #211
1 parent d21239e commit 2ba9e08

2 files changed

Lines changed: 113 additions & 0 deletions

File tree

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Creator Query Normalization
2+
3+
This document describes how raw query parameters for creator lookup endpoints are
4+
normalized before use. See [`src/utils/public-query-parse.utils.ts`](../../src/utils/public-query-parse.utils.ts)
5+
for the generic Zod-based validation layer that wraps these parameters.
6+
7+
## Overview
8+
9+
Creator lookup endpoints accept three optional identifier fields. Each field is
10+
read directly from `req.query` by
11+
[`parseCreatorPublicQuery`](../../src/utils/creator-public-query.util.ts) and
12+
forwarded to the service layer as-is. No coercion, trimming, or case-folding is
13+
applied at the utility level — normalization is the caller's responsibility.
14+
15+
| Query key | Constant | Typical format |
16+
| :--------------- | :------------------------------------------ | :---------------------- |
17+
| `creatorId` | `CREATOR_PUBLIC_QUERY_KEYS.CREATOR_ID` | UUID v4 string |
18+
| `creatorAddress` | `CREATOR_PUBLIC_QUERY_KEYS.CREATOR_ADDRESS` | Stellar public key (G…) |
19+
| `username` | `CREATOR_PUBLIC_QUERY_KEYS.USERNAME` | Lowercase handle |
20+
21+
## Field-by-field rules
22+
23+
### `creatorId`
24+
25+
Identifies a creator by their internal database UUID.
26+
27+
**Rules applied by callers before querying:**
28+
29+
- Must be a valid UUID v4 (`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`).
30+
- Leading/trailing whitespace should be stripped.
31+
- Case is insignificant for UUID comparison but the stored value is lowercase —
32+
normalize to lowercase before querying.
33+
34+
**Before / after examples:**
35+
36+
| Raw query string | Normalized value used in query |
37+
| :------------------------ | :----------------------------------- |
38+
| `creatorId=ABC-123` | rejected — not a valid UUID |
39+
| `creatorId= 3f6a1b2c-… ` | `3f6a1b2c-…` (whitespace stripped) |
40+
| `creatorId=3F6A1B2C-…` | `3f6a1b2c-…` (lowercased) |
41+
| `creatorId=3f6a1b2c-…` | `3f6a1b2c-…` (unchanged, valid UUID) |
42+
43+
---
44+
45+
### `creatorAddress`
46+
47+
Identifies a creator by their linked Stellar public key.
48+
49+
**Rules applied by callers before querying:**
50+
51+
- Must start with `G` and be 56 characters (Stellar ed25519 public key format).
52+
- Leading/trailing whitespace should be stripped.
53+
- Stellar addresses are case-sensitive — do **not** normalize case.
54+
55+
**Before / after examples:**
56+
57+
| Raw query string | Normalized value used in query |
58+
| :-------------------------- | :---------------------------------------------- |
59+
| `creatorAddress= GABC…XYZ ` | `GABC…XYZ` (whitespace stripped) |
60+
| `creatorAddress=gabc…xyz` | rejected — lowercase Stellar address is invalid |
61+
| `creatorAddress=GABC…XYZ` | `GABC…XYZ` (unchanged, valid address) |
62+
| `creatorAddress=SHORTKEY` | rejected — not 56 characters |
63+
64+
---
65+
66+
### `username`
67+
68+
Identifies a creator by their public handle.
69+
70+
**Rules applied by callers before querying:**
71+
72+
- Leading/trailing whitespace should be stripped.
73+
- Stored usernames are lowercase — normalize to lowercase before querying so
74+
that `Alice`, `alice`, and `ALICE` all resolve to the same creator.
75+
- Empty string after trimming is treated as absent (no filter applied).
76+
77+
**Before / after examples:**
78+
79+
| Raw query string | Normalized value used in query |
80+
| :--------------------- | :----------------------------- |
81+
| `username=Alice` | `alice` |
82+
| `username= Alice ` | `alice` (trimmed + lowercased) |
83+
| `username=MUSIC_MAKER` | `music_maker` |
84+
| `username=` | _(parameter ignored)_ |
85+
86+
## Validation integration
87+
88+
These normalization rules are enforced at the route/controller layer using the
89+
`parsePublicQuery` helper from
90+
[`src/utils/public-query-parse.utils.ts`](../../src/utils/public-query-parse.utils.ts).
91+
A Zod schema wraps each field, applies `.trim()` and `.toLowerCase()` transforms
92+
where appropriate, and returns a typed `{ ok: true, data }` result or a
93+
structured `{ ok: false, details }` error array suitable for a `400` response.
94+
95+
```ts
96+
// Example schema used with parsePublicQuery
97+
const creatorLookupSchema = z.object({
98+
creatorId: z.string().uuid().optional(),
99+
creatorAddress: z.string().length(56).startsWith('G').optional(),
100+
username: z.string().trim().toLowerCase().optional(),
101+
});
102+
```
103+
104+
## Related files
105+
106+
- [`src/utils/creator-public-query.util.ts`](../../src/utils/creator-public-query.util.ts) — raw query extraction
107+
- [`src/utils/public-query-parse.utils.ts`](../../src/utils/public-query-parse.utils.ts) — Zod-based parse + validation
108+
- [`src/constants/creator-public-query.constants.ts`](../../src/constants/creator-public-query.constants.ts) — query key constants
109+
- [`src/modules/creator/`](../../src/modules/creator/) — creator module routes and services

src/utils/public-query-parse.utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ export type PublicQueryParseResult<T> =
1515
* This helper is intentionally small and focused:
1616
* - maps `ZodError` into `{ field, message }[]` for API validation responses
1717
* - does not add runtime behavior beyond schema parsing and error shaping
18+
*
19+
* For creator-specific query normalization rules (trimming, case-folding,
20+
* format validation) and before/after examples, see:
21+
* docs/api/creator-query-normalization.md
1822
*/
1923
export function parsePublicQuery<S extends ZodTypeAny>(
2024
schema: S,

0 commit comments

Comments
 (0)