一键导入
review-api-endpoint
Use when reviewing PRs that add or modify API endpoints in the Smartsheet Java SDK, before approving changes
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when reviewing PRs that add or modify API endpoints in the Smartsheet Java SDK, before approving changes
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when cutting a new release of the Smartsheet Java SDK — version bump, changelog, tag, and GitHub Release
Use when adding or modifying API endpoints in the Smartsheet Java SDK, before writing implementation code or tests
| name | review-api-endpoint |
| description | Use when reviewing PRs that add or modify API endpoints in the Smartsheet Java SDK, before approving changes |
This skill ensures API endpoint reviews validate against OpenAPI specifications, verify complete test coverage per TESTING.md, and enforce SDK architecture patterns from ADVANCED.md.
Core principle: Cannot approve without validating every field against OpenAPI spec, verifying all 6 mandatory tests exist, and detecting breaking changes.
CRITICAL: Breaking changes detection is the HIGHEST PRIORITY review concern. Even perfect implementation must be blocked if it contains undisclosed breaking changes.
Use when:
Do NOT use for:
digraph review_endpoint {
"Start Review" [shape=doublecircle];
"Identify endpoint being added/changed" [shape=box];
"Check for BREAKING CHANGES" [shape=box, style=filled, fillcolor=yellow];
"Breaking changes found?" [shape=diamond];
"PR explicitly mentions breaking changes?" [shape=diamond];
"BLOCK - Undisclosed breaking changes" [shape=box, style=filled, fillcolor=red];
"Note: Requires major version" [shape=box];
"Fetch OpenAPI spec" [shape=box];
"Spec has endpoint?" [shape=diamond];
"BLOCK - Request spec" [shape=box, style=filled, fillcolor=red];
"Create validation checklist" [shape=box];
"Validate ALL model fields vs spec" [shape=box];
"All fields match?" [shape=diamond];
"REQUEST CHANGES - Field mismatch" [shape=box, style=filled, fillcolor=orange];
"Verify AbstractResources pattern used" [shape=box];
"Pattern correct?" [shape=diamond];
"REQUEST CHANGES - Wrong pattern" [shape=box, style=filled, fillcolor=orange];
"Count test types" [shape=box];
"All 6 tests present?" [shape=diamond];
"REQUEST CHANGES - Missing tests" [shape=box, style=filled, fillcolor=orange];
"Validate test quality per TESTING.md" [shape=box];
"Tests follow strict rules?" [shape=diamond];
"REQUEST CHANGES - Test quality issues" [shape=box, style=filled, fillcolor=orange];
"APPROVE" [shape=box, style=filled, fillcolor=green];
"Start Review" -> "Identify endpoint being added/changed";
"Identify endpoint being added/changed" -> "Check for BREAKING CHANGES";
"Check for BREAKING CHANGES" -> "Breaking changes found?";
"Breaking changes found?" -> "PR explicitly mentions breaking changes?" [label="yes"];
"Breaking changes found?" -> "Fetch OpenAPI spec" [label="no"];
"PR explicitly mentions breaking changes?" -> "BLOCK - Undisclosed breaking changes" [label="no"];
"PR explicitly mentions breaking changes?" -> "Note: Requires major version" [label="yes"];
"Note: Requires major version" -> "Fetch OpenAPI spec";
"Fetch OpenAPI spec" -> "Spec has endpoint?";
"Spec has endpoint?" -> "BLOCK - Request spec" [label="no"];
"Spec has endpoint?" -> "Create validation checklist" [label="yes"];
"Create validation checklist" -> "Validate ALL model fields vs spec";
"Validate ALL model fields vs spec" -> "All fields match?";
"All fields match?" -> "REQUEST CHANGES - Field mismatch" [label="no"];
"All fields match?" -> "Verify AbstractResources pattern used" [label="yes"];
"Verify AbstractResources pattern used" -> "Pattern correct?";
"Pattern correct?" -> "REQUEST CHANGES - Wrong pattern" [label="no"];
"Pattern correct?" -> "Count test types" [label="yes"];
"Count test types" -> "All 6 tests present?";
"All 6 tests present?" -> "REQUEST CHANGES - Missing tests" [label="no"];
"All 6 tests present?" -> "Validate test quality per TESTING.md" [label="yes"];
"Validate test quality per TESTING.md" -> "Tests follow strict rules?";
"Tests follow strict rules?" -> "REQUEST CHANGES - Test quality issues" [label="no"];
"Tests follow strict rules?" -> "APPROVE" [label="yes"];
}
⚠️ INCREDIBLY IMPORTANT: Breaking changes detection is the HIGHEST PRIORITY concern in API reviews.
This check happens BEFORE all other validation. Even perfect code must be BLOCKED if it contains undisclosed breaking changes.
Breaking changes in a public SDK:
Rule: Unless PR description EXPLICITLY mentions "breaking change" or "breaking changes", ANY detected breaking change MUST result in BLOCKED approval.
Compare git diff of public interfaces, classes, and methods. Check for:
For each modified file in PR:
# Get list of modified public files
git diff --name-only origin/mainline...HEAD | grep -E '(Resources\.java|models/.*\.java)'
# For each file, check what changed
git diff origin/mainline...HEAD path/to/File.java
Look for:
Example 1: Method Rename
// OLD (mainline)
public TokenPaginatedResult<UserPlan> listUserPlans(long userId, String lastKey, Long maxItems)
// NEW (PR)
public TokenPaginatedResult<UserPlan> getUserPlans(long userId, String lastKey, Long maxItems)
BREAKING: Method name changed. All user code calling listUserPlans() breaks.
Example 2: Field Removal
// OLD
private Boolean isInternal;
public Boolean getIsInternal() { return isInternal; }
// NEW
// (field removed, getter removed)
BREAKING: Public getter removed. All user code calling getIsInternal() breaks.
Example 3: Return Type Change
// OLD
public List<Sheet> listSheets()
// NEW
public PagedResult<Sheet> listSheets()
BREAKING: Return type changed. User code assigning to List<Sheet> breaks.
Example 4: Parameter Addition (SEEMS safe, ACTUALLY breaking)
// OLD
public Report createReport(ReportDefinition definition)
// NEW
public Report createReport(ReportDefinition definition, Boolean validate)
BREAKING: New required parameter. All existing calls missing the parameter break.
After detecting breaking changes:
If breaking changes found AND not mentioned:
🚫 BLOCK APPROVAL
CRITICAL: This PR contains BREAKING CHANGES that are not disclosed in the PR description.
Breaking changes detected:
- [List each breaking change with file:line reference]
**This PR CANNOT be approved** unless:
1. PR description explicitly mentions "breaking change" or "breaking changes"
2. Justification provided for why breaking change is necessary
3. Planned for major version release (e.g., 4.0.0)
4. Migration path documented
Semantic versioning requires major version bump for ANY breaking change.
If breaking changes found AND mentioned:
⚠️ WARNING: Breaking Changes Detected
This PR contains breaking changes (acknowledged by author):
- [List each breaking change]
Before approval, verify:
- [ ] Planned for major version release (X.0.0)
- [ ] CHANGELOG updated with breaking change notice
- [ ] Migration guide created/updated
- [ ] Sufficient justification provided
Proceed with review of other aspects.
| Excuse | Reality |
|---|---|
| "It's an improvement" | Improvements can be breaking. If it changes API surface, it's breaking. |
| "API changed, SDK should match" | SDK breaking changes are independent of API changes. Still breaking. |
| "It's technically compatible" | Behavior changes break user expectations. Still breaking. |
| "We deprecated it already" | Deprecation warns about future removal. Removal itself is breaking. |
| "Better name" / "More intuitive" | Renaming is breaking. No matter how much better. |
| "Only affects edge cases" | Any code breakage is breaking, regardless of how few users affected. |
| "Tests pass" | Tests don't represent all user code in the wild. |
| "We'll document it" | Documentation doesn't make breaking changes non-breaking. |
Breaking changes ARE acceptable when:
But still must be FLAGGED in review as requiring major version.
MANDATORY: Cannot review without spec.
For public endpoints:
# Fetch Smartsheet public API spec
curl -s https://developers.smartsheet.com/_spec/api/smartsheet/openapi.json > /tmp/openapi.json
# Find the endpoint (example: GET /users/{userId}/plans)
jq '.paths."/users/{userId}/plans".get' /tmp/openapi.json
For unreleased endpoints:
If spec is unavailable: STOP. Request spec before continuing review.
For each model class in the PR, extract all properties from OpenAPI spec and create a validation checklist.
Example: Validating UserPlan model
OpenAPI spec shows:
UserPlan:
required: [planId, seatType]
properties:
planId:
type: integer
format: int64
seatType:
type: string
enum: [MEMBER, VIEWER, EDITOR, ADMIN, CONTRIBUTOR]
seatTypeLastChangedAt:
type: string
format: date-time
provisionalExpirationDate:
type: string
format: date-time
isInternal:
type: boolean
Validation checklist:
planId field exists as Long (int64 → Long)planId is documented as requiredseatType field exists as SeatType enumseatType is documented as requiredSeatType enum has all values from specseatTypeLastChangedAt field exists as ZonedDateTimeseatTypeLastChangedAt is optional (no required marking)provisionalExpirationDate field exists as ZonedDateTimeprovisionalExpirationDate is optionalisInternal field exists as BooleanisInternal is optionalCRITICAL: Must validate EVERY field, not spot-check.
For each field in checklist:
# Verify field exists in model class
grep -n "private Long planId" UserPlan.java
grep -n "private SeatType seatType" UserPlan.java
OpenAPI type → Java type mapping:
| OpenAPI Type | Format | Java Type |
|---|---|---|
| integer | int32 | Integer |
| integer | int64 | Long |
| string | - | String |
| string | date-time | ZonedDateTime |
| string | date | LocalDate |
| boolean | - | Boolean |
| number | float | Float |
| number | double | Double |
| array | - | List |
| object | - | Custom class |
If property is object type, recursively validate nested model:
If property is enum:
toString() method for serializationReference: ADVANCED.md → Request Lifecycle, Resource Module Organization sections
REQUIRED: Implementation MUST use AbstractResources, not HttpClient directly.
Correct patterns:
// GET single resource
return getResource(path, ResponseClass.class);
// GET collection with pagination
return listResourcesWithWrapper(path, ResponseClass.class, parameters);
// GET with token pagination
return listResourcesWithTokenPagination(path, ResponseClass.class, parameters);
// POST create
return createResource(path, ResponseClass.class, requestObject);
// PUT update
return updateResource(path, ResponseClass.class, requestObject);
// DELETE
return deleteResource(path, ResponseClass.class);
Red flag: Direct HttpClient usage bypasses retry logic, logging, error handling.
Verify optional query parameters:
// ✅ GOOD: Null check before adding
if (lastKey != null) {
parameters.put("lastKey", lastKey);
}
// ❌ BAD: Always adds (causes empty params)
parameters.put("lastKey", lastKey);
Match spec pagination type:
Verify implementation uses correct listResources* method for pagination type.
Reference: TESTING.md → The 6 Mandatory Test Case Types section
Count tests in test file. Must find exactly 6 (or more).
Required tests:
testXxxGeneratedUrlIsCorrect - URL and query param validationtestXxxAllResponseBodyProperties - Full response with all optional fieldstestXxxRequiredResponseBodyProperties - Minimal response (if WireMock mapping exists)testXxxError400Response - 4xx client error handlingtestXxxError500Response - 5xx server error handlingIf any test is missing: REQUEST CHANGES with specific list of missing tests.
| Developer Says | Your Response |
|---|---|
| "Required/All tests are redundant" | "They test different failure modes: minimal API responses vs full responses. Both required." |
| "3 tests are good coverage" | "TESTING.md mandates 6 test types. 'Good' ≠ 'complete'. Request missing tests." |
| "400/500 tests are the same" | "4xx = client errors (not retried), 5xx = server errors (may retry). Different paths." |
| "Behavioral tests are nice-to-have" | "TESTING.md lists them as test type #6. Mandatory, not optional." |
Reference: TESTING.md → Strict Assertion Rules section
For EACH test, verify:
// ❌ BAD: Spot checking
assertThat(response.getId()).isEqualTo(123);
assertThat(response.getName()).isEqualTo("Test");
// (missing 10 other fields)
// ✅ GOOD: All fields validated
assertThat(response.getId()).isEqualTo(123);
assertThat(response.getName()).isEqualTo("Test");
assertThat(response.getDescription()).isEqualTo("...");
assertThat(response.getCategories()).hasSize(2);
// (all fields explicitly checked)
// ❌ BAD: Existence check only
assertThat(receivedQueryParams.containsKey("maxItems")).isTrue();
// ✅ GOOD: Complete object validation
assertThat(receivedQueryParams.get("maxItems").getValues()).isEqualTo(List.of("100"));
// ✅ Required for create/update endpoints
String requestBody = wiremockRequest.getBodyAsString();
ObjectMapper objectMapper = new ObjectMapper();
String expectedJson = objectMapper.writeValueAsString(EXPECTED_REQUEST_BODY);
assertThat(objectMapper.readTree(requestBody)).isEqualTo(objectMapper.readTree(expectedJson));
If test quality issues found: REQUEST CHANGES with specific fixes needed.
Tests reference WireMock stub mappings. Verify they exist:
# Check if mapping file exists in smartsheet-sdk-tests repo
ls smartsheet-sdk-tests/mappings/*list-user-plans*
If mappings missing: REQUEST CHANGES - tests will fail at runtime.
ONLY approve if ALL checks pass:
If ANY check fails: REQUEST CHANGES with specific actionable feedback.
If breaking changes detected without disclosure: BLOCK IMMEDIATELY - do not proceed with other checks.
Stop and reject when you hear:
Breaking Changes (CRITICAL):
Review Quality:
All of these mean: REQUEST CHANGES or BLOCK. Do not compromise.
| Excuse | Reality |
|---|---|
| Breaking Changes | |
| "It's an improvement" | Improvements can be breaking. If API surface changes, it's breaking. |
| "API changed, SDK should match" | SDK breaking changes are independent. Still requires major version. |
| "Technically compatible" | Behavior changes break user expectations. Still breaking. |
| "We deprecated it already" | Deprecation warns. Removal itself is breaking. |
| "Better name/More intuitive" | Renaming is breaking. No matter how much better. |
| "Only edge cases affected" | Any code breakage is breaking, regardless of frequency. |
| "Tests pass" | Tests don't represent all user code. Breaking is breaking. |
| "We'll document it" | Documentation doesn't make breaking changes non-breaking. |
| Review Quality | |
| "Senior dev wrote it" | Authority doesn't prevent spec drift. Validate every field. |
| "Tests pass" (correctness) | Tests can pass with wrong types, missing fields. Spec is source of truth. |
| "Merge today" | Time pressure doesn't justify shipping broken API contracts. |
| "Tedious to check 50 fields" | One missed field = production bug. This is non-negotiable. |
| "3 tests are good" | TESTING.md mandates 6. "Good" ≠ "complete". |
| "Required/all tests redundant" | Different failure modes. Both catch different bugs. |
| "400/500 tests the same" | 4xx vs 5xx = client vs server errors, different retry behavior. |
| "Later we'll add X" | Later never comes. Complete now or block. |
Problem: Approving PRs with breaking changes because they "improve" the API or "match the updated API spec."
Fix: Check for breaking changes FIRST, before any other validation. Block if breaking changes not disclosed in PR description.
Problem: Trusting implementation matches spec without verification.
Fix: Fetch OpenAPI spec and validate EVERY field before approving.
Problem: Approving PR with 3 tests because "it's good coverage."
Fix: Count tests. Must have all 6 types. Request specific missing tests.
Problem: Validating only id/name fields, assuming rest are correct.
Fix: Create checklist from spec. Validate ALL fields. No sampling.
Problem: Allowing direct HttpClient usage because "it's simpler."
Fix: Enforce AbstractResources pattern usage. No exceptions.
Problem: Not verifying tests have type validation.
Fix: Scan each test for assertThat(response).isInstanceOf(...). Request if missing.
Problem: Assuming passing tests mean correct implementation.
Fix: Passing tests ≠ correct API contract. Spec validation is mandatory.
Problem: Accepting breaking changes because they make the API "better" or "more consistent."
Fix: Quality of change doesn't matter. If it breaks compatibility, it's breaking. Must be disclosed.
Without rigorous review (especially breaking changes detection):
With this review process: