원클릭으로
review-api-endpoint
Use when reviewing API endpoint implementations in the Smartsheet JavaScript SDK, before approval or merge
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Use when reviewing API endpoint implementations in the Smartsheet JavaScript SDK, before approval or merge
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Use when cutting a new release of the Smartsheet JavaScript SDK — version bump, changelog, tag, and GitHub Release
Use when adding or modifying API endpoints in the Smartsheet JavaScript SDK, before writing any code
| name | review-api-endpoint |
| description | Use when reviewing API endpoint implementations in the Smartsheet JavaScript SDK, before approval or merge |
Systematic code review process for API endpoint implementations in the Smartsheet JavaScript SDK. Verifies OpenAPI spec alignment, TypeScript correctness, test completeness, and pattern compliance.
Core principle: Verify, don't trust. Check every claim against spec and code.
Use when:
Do NOT use for:
YOU MUST have:
Where to get OpenAPI spec:
Where to get WireMock mappings:
If either missing: STOP. Request both OpenAPI spec and WireMock mappings before proceeding with review.
digraph review_endpoint {
"Start Review" [shape=doublecircle];
"Have OpenAPI spec and WireMock mappings?" [shape=diamond];
"STOP - Request spec and mappings" [shape=box, style=filled, fillcolor=red];
"Check for breaking changes" [shape=box, style=filled, fillcolor=orange];
"Breaking changes found?" [shape=diamond];
"PR explicitly mentions breaking changes?" [shape=diamond];
"BLOCK - Undisclosed breaking changes" [shape=box, style=filled, fillcolor=red];
"Locate implementation files" [shape=box];
"Check types alignment" [shape=box];
"Types match spec?" [shape=diamond];
"Check method implementation" [shape=box];
"Method correct?" [shape=diamond];
"Check 4 required tests exist" [shape=box];
"Required tests present?" [shape=diamond];
"Check optional tests match mappings" [shape=box];
"Verify test assertions and patterns" [shape=box];
"Assertions correct?" [shape=diamond];
"Verify spec alignment" [shape=box];
"Spec aligned?" [shape=diamond];
"Document issues" [shape=box];
"REJECT - needs fixes" [shape=box, style=filled, fillcolor=yellow];
"APPROVE" [shape=box, style=filled, fillcolor=green];
"Done" [shape=doublecircle];
"Start Review" -> "Have OpenAPI spec and WireMock mappings?";
"Have OpenAPI spec and WireMock mappings?" -> "STOP - Request spec and mappings" [label="no"];
"Have OpenAPI spec and WireMock mappings?" -> "Check for breaking changes" [label="yes"];
"Check for breaking changes" -> "Breaking changes found?";
"Breaking changes found?" -> "Locate implementation files" [label="no"];
"Breaking changes found?" -> "PR explicitly mentions breaking changes?" [label="yes"];
"PR explicitly mentions breaking changes?" -> "Locate implementation files" [label="yes"];
"PR explicitly mentions breaking changes?" -> "BLOCK - Undisclosed breaking changes" [label="no"];
"Locate implementation files" -> "Check types alignment";
"Check types alignment" -> "Types match spec?";
"Types match spec?" -> "Check method implementation" [label="yes"];
"Types match spec?" -> "Document issues" [label="no"];
"Check method implementation" -> "Method correct?";
"Method correct?" -> "Check 4 required tests exist" [label="yes"];
"Method correct?" -> "Document issues" [label="no"];
"Check 4 required tests exist" -> "Required tests present?";
"Required tests present?" -> "Check optional tests match mappings" [label="yes"];
"Required tests present?" -> "Document issues" [label="no"];
"Check optional tests match mappings" -> "Verify test assertions and patterns";
"Verify test assertions and patterns" -> "Assertions correct?";
"Assertions correct?" -> "Verify spec alignment" [label="yes"];
"Assertions correct?" -> "Document issues" [label="no"];
"Verify spec alignment" -> "Spec aligned?";
"Spec aligned?" -> "APPROVE" [label="yes"];
"Spec aligned?" -> "Document issues" [label="no"];
"Document issues" -> "REJECT - needs fixes";
"REJECT - needs fixes" -> "Done";
"BLOCK - Undisclosed breaking changes" -> "Done";
"APPROVE" -> "Done";
}
⚠️ THIS IS THE MOST IMPORTANT PHASE. DO NOT SKIP.
Breaking changes in a public SDK destroy client code. You MUST check for breaking changes BEFORE reviewing anything else.
What is a breaking change?
A breaking change is ANY modification that would cause existing client code to:
CRITICAL: If breaking changes exist and PR does NOT explicitly mention them, BLOCK immediately.
Compare the PR's changes against the existing SDK contract:
Modified Types (check lib/{apiGroup}/types.ts):
?)?)Modified Method Signatures (check API interfaces):
How to check for breaking changes:
# Compare current main branch with PR branch
git diff main..HEAD -- lib/{apiGroup}/types.ts
# Look for these patterns in the diff:
# - Lines removed from interfaces
# - `propertyName:` → `propertyName?:` (made optional)
# - `propertyName?:` → `propertyName:` (made required)
# - Type changes: `string` → `number`, `Type1` → `Type2`
# - Methods removed from API interface
Decision tree:
Found breaking changes?
├─ NO → Continue to Phase 1
└─ YES → Check PR description
├─ PR explicitly mentions breaking changes? (Look for keywords: "breaking change", "breaking", "major version", "⚠️")
│ ├─ YES → Continue to Phase 1 (document breaking changes in review)
│ └─ NO → **BLOCK IMMEDIATELY** - Undisclosed breaking changes
└─ Not sure if it's breaking? → Ask yourself:
"Would existing client code break if I deploy this?"
If yes → It's breaking → BLOCK unless disclosed
Common rationalizations to REJECT:
| Rationalization | Reality | Counter-Argument |
|---|---|---|
| "The new code matches the OpenAPI spec perfectly" | Spec may have changed. SDK must maintain backward compatibility unless explicitly breaking. | The spec changing doesn't give us permission to break clients. BLOCK. |
| "Types compile, tests pass" | Existing CLIENT code won't compile. Client code isn't in this repo. | Our tests pass. Their code breaks. That's what breaking change means. BLOCK. |
| "Optional fields are backward compatible" | Making REQUIRED → optional breaks code that assumes presence. | Wrong direction. Optional → required breaks. Required → optional ALSO breaks because code assumes presence. BLOCK. |
| "It's an enhancement, not a break" | Adding = enhancement. Removing/changing = break. | If existing calls fail, it's breaking. Period. BLOCK. |
| "The spec changed, we're following it" | Spec changes don't justify breaking client code without disclosure. | We don't control client upgrade cycles. Can't force breaking changes on them silently. BLOCK. |
| "Minor change, shouldn't matter" | Size doesn't determine breaking. Impact on clients does. | One character change (string → string?) destroys production apps. BLOCK. |
| "Old pattern still works" | If signature changed, old calls fail. That's breaking. | "Still works" only applies to code in this repo. Client code breaks. BLOCK. |
| "We're aligning with the official spec" | Alignment doesn't justify breaking clients without disclosure. | Spec correctness ≠ backward compatibility. These are independent concerns. BLOCK. |
| "The spec was updated and we were out of sync" | Being out of sync doesn't mean breaking is acceptable. | Maybe the spec was wrong before, or we were wrong. Either way, clients depend on current behavior. BLOCK. |
| "All our tests pass" | Your tests aren't client code. | Tests in this repo test OUR code. Client code isn't here. BLOCK. |
| "It's just a type change" | Type changes break client code at compile time. | TypeScript clients won't compile. JavaScript clients get runtime errors. BLOCK. |
| "Technically backward compatible" | If client code breaks, it's not backward compatible. | "Technically" is a weasel word. Does client code break? Yes? Then BLOCK. |
Examples of breaking changes:
// ❌ BREAKING: Required field made optional
interface User {
id: number;
email: string;
firstName: string; // Before: required
firstName?: string; // After: optional - BREAKS code assuming it exists
}
// ❌ BREAKING: Parameter type changed
getUserCustomAttributes(options: {
userId: number; // Before
userId: string; // After - BREAKS code passing numbers
})
// ❌ BREAKING: Return type structure changed
// Before: Promise<CustomAttribute[]>
// After: Promise<{ data: CustomAttribute[]; totalCount: number }>
// BREAKS code expecting direct array access
// ❌ BREAKING: Method removed
interface UsersApi {
listUsers(): Promise<User[]>;
removeUser(options: { userId: number }): Promise<void>; // Removed - BREAKS calls to this method
}
// ✅ NOT BREAKING: Adding new optional parameter
getUsers(options: { includeInactive?: boolean }) // New optional param is safe
// ✅ NOT BREAKING: Adding new method
getUserCustomAttributes(...) // New method doesn't break existing code
// ✅ NOT BREAKING: Adding new optional property
interface User {
id: number;
customAttributes?: CustomAttribute[]; // New optional property is safe
}
When in doubt:
BLOCK means:
Why you might resist blocking (and why you should anyway):
You might feel:
Reality:
Remember: This is a PUBLIC SDK. Your approval ships code that thousands of client applications depend on. One undisclosed breaking change destroys production systems.
Find implementation:
# TypeScript interface
grep -r "methodName" lib/<resource>/types.ts
# Implementation
grep -r "methodName" lib/<resource>/index.ts
grep -r "methodName" lib/<resource>/index.js
# Tests
find test/mock-api/<resource>/ -name "*method*.spec.ts"
Required files:
If files missing: Document as blocker. Cannot review without all files.
Gold standard reference: Compare structure and patterns to test/mock-api/reports/ (TESTING.md line 99).
Check types file (lib/{apiGroup}/types.ts - e.g., lib/reports/types.ts):
CRITICAL: All type definitions MUST be in lib/{apiGroup}/types.ts, not scattered across multiple files.
RequestOptions<QueryParams, Body>SmartsheetClient in lib/types/SmartsheetClient.tsVerification command:
# Check if API interface is in SmartsheetClient
grep -r "ReportsApi" lib/types/SmartsheetClient.ts
Spec alignment verification:
// From OpenAPI spec
parameters: [
{ name: "includeDeleted", in: "query", required: false, schema: { type: "boolean" } }
]
// Must match in code
export interface GetUserCustomAttributesQueryParameters {
includeDeleted?: boolean; // Optional = ? in TypeScript
}
Common type issues:
| Issue | How to Spot | Fix Required |
|---|---|---|
| Missing optional marker (?) | Spec says required:false, code has no ? | Add ? to property |
| Wrong type | Spec says integer, code says string | Change type to match spec |
| Missing property | Spec has property, code doesn't | Add missing property |
| Extra property | Code has property, spec doesn't | Remove or verify spec |
Check implementation file (lib//index.ts):
{ ...optionsToSend, ...urlOptions, ...getOptions }requestor.<method>(options, callback)URL path verification:
// OpenAPI spec: /users/{userId}/customAttributes
// Implementation must match
const buildUrl = (opts: { userId: number }) =>
options.apiUrls.users + '/' + opts.userId + '/customAttributes';
HTTP verb mapping:
| OpenAPI Method | requestor Method |
|---|---|
| GET | requestor.get() |
| POST | requestor.post() |
| PUT | requestor.put() |
| DELETE | requestor.delete() |
Check test file (test/mock-api//.spec.ts):
Reference: See test/mock-api/reports/ for gold standard test examples per TESTING.md.
4 REQUIRED TESTS (must be present):
Test 1: <method> generated url is correct
.toEqual({}))findWireMockRequest(requestId) from test/mock-api/utils/utils.ts.toEqual() Test 2: <method> all response body properties
.toEqual() assertion.toEqual('')) Test 3: <method> error 400 response
x-test-name: '/errors/400-response'error.statusCode === 400error.message Test 4: <method> error 500 response
x-test-name: '/errors/500-response'error.statusCode === 500error.message2 OPTIONAL TESTS (conditional):
Test 5: <method> required response body properties (ONLY if WireMock mapping exists)
.toEqual() assertionrequired: true in specTest 6: Endpoint-specific test (if applicable and mapping exists)
Additional verification:
createClient() from test/mock-api/utils/utils.tsReportDestinationType.FOLDER), NOT raw stringsx-test-name matches an actual WireMock mappingx-request-id and x-test-name in customPropertiesTest pattern verification:
// ✅ CORRECT - Whole object assertion
expect(response).toEqual({
data: [...],
totalCount: 2
});
// ❌ INCORRECT - Property-by-property
expect(response.data.length).toBe(2);
expect(response.totalCount).toBe(2);
// ✅ CORRECT - Query params as object
const queryParamsObject = Object.fromEntries(parsedUrl.searchParams);
expect(queryParamsObject).toEqual({ includeDeleted: 'true' });
// ❌ INCORRECT - Individual param checks
expect(parsedUrl.searchParams.get('includeDeleted')).toBe('true');
// ✅ CORRECT - Using enums
expect(report.destination.type).toEqual(ReportDestinationType.FOLDER);
// ❌ INCORRECT - Raw strings
expect(report.destination.type).toEqual('FOLDER');
Verify WireMock mapping alignment:
# Check available mappings for the resource
ls smartsheet-sdk-tests/wiremock/<resource>/
# Or if user-provided
ls path/to/mappings/<resource>/
# Verify test's x-test-name matches a mapping file
grep "x-test-name" test/mock-api/<resource>/<method>.spec.ts
Critical verification - DO NOT SKIP:
1. Request Parameters Alignment:
Extract from spec:
curl -s https://developers.smartsheet.com/_spec/api/smartsheet/openapi.json | \
jq '.paths."/users/{userId}/customAttributes".get.parameters'
Compare with TypeScript interface:
? in TypeScript)2. Response Schema Alignment:
Extract from spec:
curl -s https://developers.smartsheet.com/_spec/api/smartsheet/openapi.json | \
jq '.paths."/users/{userId}/customAttributes".get.responses."200".content."application/json".schema'
Compare with TypeScript interface:
3. Test Response Alignment:
Check test file's all_response_properties test:
Check test file's required_response_properties test:
required: true in specPriority order: Breaking changes are checked FIRST, before all other issues.
| Category | Status | Action |
|---|---|---|
| Breaking changes without disclosure | 🚨 BLOCK IMMEDIATELY | Stop review. Document breaking changes. Request PR author explicitly acknowledge them. Do NOT continue review. |
| Missing OpenAPI spec | 🛑 BLOCK | Request spec before review |
| Missing WireMock mappings | 🛑 BLOCK | Request mappings before review |
| Breaking changes WITH disclosure | ⚠️ DOCUMENT | Note in review, continue review, approve only if everything else passes |
| Missing test file | 🛑 BLOCK | Request tests |
Types not in lib/{apiGroup}/types.ts | 🛑 BLOCK | Move all types to correct file |
| API interface not in SmartsheetClient | 🛑 BLOCK | Add to lib/types/SmartsheetClient.ts |
| < 4 required tests | 🛑 BLOCK | Request missing required tests |
| Optional test WITHOUT WireMock mapping | 🛑 BLOCK | Remove test or provide mapping |
| Test x-test-name references non-existent mapping | 🛑 BLOCK | Fix x-test-name or add mapping |
| Type mismatch with spec | 🛑 BLOCK | Fix types to match spec |
| URL path wrong | 🛑 BLOCK | Fix URL to match spec |
| Wrong HTTP verb | 🛑 BLOCK | Fix verb to match spec |
| Property-by-property assertions | ⚠️ REQUEST CHANGES | Change to .toEqual() |
| Raw strings instead of enums | ⚠️ REQUEST CHANGES | Use enum values |
| Not using helper functions (createClient, findWireMockRequest) | ⚠️ REQUEST CHANGES | Use helpers from utils.ts |
| Missing optional test when WireMock mapping exists | ⚠️ REQUEST CHANGES | Add optional test |
| Missing optional marker (?) | ⚠️ REQUEST CHANGES | Add ? to optional properties |
| Poor test names | ⚠️ REQUEST CHANGES | Follow TESTING.md naming convention |
| Missing JSDoc | 💬 COMMENT | Add documentation |
| Minor style issues | 💬 COMMENT | Nitpick |
Symptom: "Code matches spec, tests pass, approved"
Problem: Didn't check if changes break existing client code
Impact: CATASTROPHIC - Deploys SDK update that breaks all client applications
Fix:
git diff main..HEAD -- lib/{apiGroup}/types.ts FIRSTRed flags you're about to make this mistake:
Symptom: "Looks good, tests pass, approved"
Problem: Didn't verify spec alignment
Fix: Actually compare implementation to OpenAPI spec. Line by line.
Symptom: "I see all required tests exist, approved"
Problem: Didn't check test content
Fix: Read each test. Verify assertions use .toEqual() with whole objects.
Symptom: "Types compile, approved"
Problem: TypeScript types don't match OpenAPI spec
Fix: Compare TypeScript interface to spec schema. Check every property.
Symptom: "Tests look fine, approved"
Problem: Optional tests exist without WireMock mappings, or x-test-name references non-existent mappings
Fix: List available mappings. Verify each test's x-test-name matches a mapping file.
Symptom: "Tests assert values correctly, approved"
Problem: Tests use raw strings ('FOLDER') instead of enums (ReportDestinationType.FOLDER)
Fix: Search for raw string literals in test assertions. Request enum usage.
Symptom: "Tests create client and retrieve requests, approved"
Problem: Tests inline client creation or request retrieval instead of using utils.ts helpers
Fix: Verify tests use createClient() and findWireMockRequest() from utils.ts.
Symptom: "Types look good, approved"
Problem: Types scattered across multiple files instead of in lib/{apiGroup}/types.ts
Fix: Verify all types are in the correct single file: lib/{apiGroup}/types.ts.
Symptom: "API interface defined, approved"
Problem: Forgot to check if API interface added to SmartsheetClient
Fix: Verify API interface is in lib/types/SmartsheetClient.ts if the interface exists.
Symptom: "Implementation follows patterns, approved"
Problem: Didn't verify against spec
Fix: Go through full checklist. Verify every item.
These observations mean you need to investigate further:
⚠️ CRITICAL - Breaking Changes Red Flags:
git diff to compare against main branchAll of these ignore the question: "Does existing CLIENT code still work?"
Other Red Flags:
None of these substitute for spec verification and TESTING.md compliance.
Structure your review feedback clearly:
## Review: [Endpoint Name]
### Phase 0: Breaking Changes (CRITICAL)
- [ ] Checked for breaking changes: [pass/fail]
- [ ] Breaking changes found: [yes/no]
- [ ] If yes, PR explicitly mentions breaking changes: [yes/no/n/a]
**Breaking changes details:**
[List any breaking changes found, or "None" if no breaking changes]
**If breaking changes found without disclosure: STOP HERE - BLOCK IMMEDIATELY**
### Prerequisites
- [ ] OpenAPI spec provided: [link or path]
- [ ] WireMock mappings available: [link or path]
- [ ] Spec validated
- [ ] Available mappings verified
### TypeScript Types (MUST be in `lib/{apiGroup}/types.ts`)
- [ ] All types in correct file (`lib/{apiGroup}/types.ts`): [pass/fail]
- [ ] Query parameters interface: [pass/fail]
- [ ] Request body interface: [pass/fail/n/a]
- [ ] Response interfaces: [pass/fail]
- [ ] Method signature in API interface: [pass/fail]
- [ ] API interface added to SmartsheetClient: [pass/fail/n/a - interface exists: yes/no]
Issues:
- [Specific issue with line number]
### Implementation
- [ ] URL path correct: [pass/fail]
- [ ] HTTP verb correct: [pass/fail]
- [ ] Pattern compliance: [pass/fail]
Issues:
- [Specific issue with line number]
### Test Coverage (REQUIRED: 4 tests)
- [ ] Test 1 (generated url is correct): [pass/fail]
- [ ] Test 2 (all response body properties): [pass/fail]
- [ ] Test 3 (error 400 response): [pass/fail]
- [ ] Test 4 (error 500 response): [pass/fail]
### Test Coverage (OPTIONAL: conditional on mappings)
- [ ] Test 5 (required response body properties): [pass/fail/n/a - mapping exists: yes/no]
- [ ] Test 6 (endpoint-specific): [pass/fail/n/a - mapping exists: yes/no]
### Test Quality
- [ ] Using createClient() from utils.ts: [pass/fail]
- [ ] Using findWireMockRequest() from utils.ts: [pass/fail]
- [ ] Whole-object assertions (.toEqual()): [pass/fail]
- [ ] Using enums (not raw strings): [pass/fail]
- [ ] x-test-name matches WireMock mappings: [pass/fail]
- [ ] Test naming follows TESTING.md convention: [pass/fail]
Issues:
- [Specific issue with line number]
### Spec Alignment
- [ ] Request parameters match spec: [pass/fail]
- [ ] Response schema matches spec: [pass/fail]
- [ ] Required vs optional correct: [pass/fail]
Issues:
- [Specific misalignment with spec reference]
### Decision
**[APPROVE / REQUEST CHANGES / BLOCK]**
Rationale: [Brief explanation]
**Reference:** Compare implementation against gold standard in `test/mock-api/reports/`
NO APPROVAL WITHOUT BREAKING CHANGES CHECK, SPEC VERIFICATION, AND WIREMOCK VERIFICATION.
If you didn't check for breaking changes AND compare the implementation to the OpenAPI spec line by line AND verify WireMock mappings, you didn't review it.
Verification means:
git diff main..HEAD)Anything less is a rubber-stamp, not a review.
Breaking changes check is NON-NEGOTIABLE. This is a PUBLIC SDK. Breaking client code is catastrophic.
Gold standard reference: test/mock-api/reports/ per TESTING.md line 99.