|
| 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 |
0 commit comments