ワンクリックで
implement-api-endpoint
Use when adding or modifying API endpoints in the Smartsheet JavaScript SDK, before writing any code
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Use when adding or modifying API endpoints in the Smartsheet JavaScript SDK, before writing any code
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 reviewing API endpoint implementations in the Smartsheet JavaScript SDK, before approval or merge
| name | implement-api-endpoint |
| description | Use when adding or modifying API endpoints in the Smartsheet JavaScript SDK, before writing any code |
Disciplined workflow for implementing Smartsheet API endpoints in the JavaScript SDK. Ensures OpenAPI spec compliance, correct TypeScript patterns, and mandatory test coverage following TESTING.md requirements.
Core principle: OpenAPI spec is source of truth. Implementation and tests must match the spec exactly.
Use when:
Do NOT use for:
YOU MUST have BOTH before starting:
Where to get OpenAPI spec:
Where to get WireMock mappings:
If either unavailable: STOP. Ask user to provide both OpenAPI spec and WireMock mappings before proceeding.
digraph implement_endpoint {
"Start" [shape=doublecircle];
"Have OpenAPI spec and WireMock mappings?" [shape=diamond];
"STOP - Request spec and mappings" [shape=box, style=filled, fillcolor=red];
"Read ADVANCED.md sections" [shape=box];
"Read TESTING.md patterns" [shape=box];
"Extract from spec" [shape=box];
"Implement types" [shape=box];
"Implement method" [shape=box];
"Write required tests" [shape=box];
"Write optional tests if mappings exist" [shape=box];
"Verify spec alignment" [shape=diamond];
"Fix misalignment" [shape=box];
"Done" [shape=doublecircle];
"Start" -> "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?" -> "Read ADVANCED.md sections" [label="yes"];
"Read ADVANCED.md sections" -> "Read TESTING.md patterns";
"Read TESTING.md patterns" -> "Extract from spec";
"Extract from spec" -> "Implement types";
"Implement types" -> "Implement method";
"Implement method" -> "Write required tests";
"Write required tests" -> "Write optional tests if mappings exist";
"Write optional tests if mappings exist" -> "Verify spec alignment";
"Verify spec alignment" -> "Fix misalignment" [label="mismatch"];
"Fix misalignment" -> "Verify spec alignment";
"Verify spec alignment" -> "Done" [label="match"];
}
Check OpenAPI spec availability:
# If using public API spec
curl -s https://developers.smartsheet.com/_spec/api/smartsheet/openapi.json | jq '.paths' | grep -A 5 'endpoint-path'
# If user provided spec file
cat path/to/spec.json | jq '.paths."endpoint-path"'
Check WireMock mappings availability:
# If using smartsheet-sdk-tests repo (clone if needed)
git clone https://github.com/smartsheet/smartsheet-sdk-tests.git
ls smartsheet-sdk-tests/wiremock/<resource>/
# If user provided local mappings
ls path/to/mappings/<resource>/
STOP if either missing. Do not proceed without both OpenAPI spec and WireMock mappings.
Required reading from ADVANCED.md:
Key patterns to follow:
create(options) returns object with methodsget(), post(), put(), delete()Required reading from TESTING.md:
.toEqual()createClient(), findWireMockRequest() from test/mock-api/utils/utils.tstest/mock-api/reports/ (line 99) - USE AS TEMPLATEWhat to extract:
| Spec Element | Used For |
|---|---|
operationId | Method name (camelCase) |
parameters | Path params, query params, TypeScript types |
requestBody.schema | Request body TypeScript interface |
responses.200.schema | Response TypeScript interface |
required arrays | Distinguish required vs optional properties |
Example extraction:
// From spec: operationId: "getUserCustomAttributes"
// Path: /users/{userId}/customAttributes
// Parameters: userId (path, required), includeDeleted (query, optional)
// Response: { data: CustomAttribute[], totalCount?: number }
Location: lib/{apiGroup}/types.ts (e.g., lib/reports/types.ts)
MANDATORY: All type definitions for new endpoints MUST be in lib/{apiGroup}/types.ts.
What to add:
RequestOptionsReportsApi)SmartsheetClient in lib/types/SmartsheetClient.tsPattern (in lib/users/types.ts):
// Query parameters
export interface GetUserCustomAttributesQueryParameters {
includeDeleted?: boolean;
}
// Response data model
export interface CustomAttribute {
id: number;
key: string;
value: string;
createdAt?: string;
modifiedAt?: string;
}
// Response wrapper
export interface GetUserCustomAttributesResponse {
data: CustomAttribute[];
totalCount?: number;
}
// Options for the method
export interface GetUserCustomAttributesOptions
extends RequestOptions<GetUserCustomAttributesQueryParameters, undefined> {
userId: number;
}
// Add to API interface for this resource
export interface UsersApi {
// ... other methods
getUserCustomAttributes(
options: GetUserCustomAttributesOptions,
callback?: RequestCallback<GetUserCustomAttributesResponse>
): Promise<GetUserCustomAttributesResponse>;
}
Then in lib/types/SmartsheetClient.ts:
export interface SmartsheetClient {
// ... other API groups
users: UsersApi; // Add if UsersApi interface exists
}
Location: lib/<resource>/index.ts (or .js for legacy modules)
Pattern:
const getUserCustomAttributes = (
getOptions: GetUserCustomAttributesOptions,
callback?: RequestCallback<GetUserCustomAttributesResponse>
) => {
const urlOptions = { url: buildGetUserCustomAttributesUrl(getOptions) };
const requestOptions = { ...optionsToSend, ...urlOptions, ...getOptions };
return requestor.get(requestOptions, callback);
};
const buildGetUserCustomAttributesUrl = (urlOptions: { userId: number }) =>
options.apiUrls.users + '/' + urlOptions.userId + '/customAttributes';
Export in returned object:
return {
// ... other methods
getUserCustomAttributes,
};
Location: test/mock-api/<resource>/<endpoint-name>.spec.ts
GOLD STANDARD TEMPLATE: Use test/mock-api/reports/ as your template for structure and patterns (TESTING.md line 99).
4 REQUIRED tests (always implement):
describe('ResourceName - methodName endpoint tests', () => {
it('methodName generated url is correct', async () => {
// Assert: method, URL path, query params ONLY
// Query params MUST be asserted even if empty (use .toEqual({}))
// Do NOT assert request/response body
});
it('methodName all response body properties', async () => {
// Assert: request body ALWAYS
// - For POST/PUT/PATCH with body: assert the body object
// - For GET/DELETE with no body: assert .toEqual('')
// Assert: full response body
// Do NOT assert method, URL, or query params
});
it('methodName error 400 response', async () => { /* ... */ });
it('methodName error 500 response', async () => { /* ... */ });
});
2 OPTIONAL tests (implement ONLY if WireMock mapping exists):
it('methodName required response body properties', async () => {
// Include ONLY if required-properties mapping exists in WireMock
// Assert: request body ALWAYS (even if empty)
});
it('methodName [endpoint-specific behavior]', async () => {
// For unique endpoint features: pagination, scope variants, etc.
});
Follow TESTING.md patterns exactly:
createClient() from test/mock-api/utils/utils.tscrypto.randomUUID() for request trackingx-request-id and x-test-name in customPropertiesfindWireMockRequest(requestId) to retrieve request details.toEqual() (not property-by-property)Object.fromEntries(parsedUrl.searchParams)ReportDestinationType.FOLDER) not raw stringsChecklist:
operationId (camelCase).toEqual()createClient() and findWireMockRequest() helpersManual verification commands:
# Check types compile
npm run build
# Check tests exist and follow naming
ls test/mock-api/<resource>/ | grep <endpoint>
# Verify test patterns
grep "\.toEqual(" test/mock-api/<resource>/<endpoint>.spec.ts
| Mistake | Fix |
|---|---|
| "Skipping spec validation (looks simple)" | ALWAYS verify against spec, even for simple endpoints |
| "Only writing 3-4 tests (others seem redundant)" | 4 required tests are MANDATORY per TESTING.md |
| "Writing optional tests without WireMock mappings" | Only write optional tests if mappings exist |
| "Types in wrong file or multiple files" | ALL types MUST be in lib/{apiGroup}/types.ts |
| "Forgot to add API interface to SmartsheetClient" | Add to lib/types/SmartsheetClient.ts if API interface exists |
| "Property-by-property assertions" | Use whole-object .toEqual() assertions |
| "Using raw strings instead of enums" | Use enum values (e.g., ReportDestinationType.FOLDER) |
| "Not using helper functions" | Use createClient() and findWireMockRequest() from utils.ts |
| "Guessing optional vs required" | Check required arrays in OpenAPI schema |
| "Not following Reports test patterns" | Use test/mock-api/reports/ as template (TESTING.md line 99) |
| "Not reading ADVANCED.md patterns" | Read Resource Module Organization section |
| "Implementing without OpenAPI spec or mappings" | STOP - no implementation without both prerequisites |
These thoughts mean you're about to skip something important:
All of these mean: Go back to the checklist. Use Reports tests as template. Follow every step.
Use this checklist for every endpoint:
Before writing code:
TypeScript types (in lib/{apiGroup}/types.ts):
Implementation:
Tests:
createClient() from test/mock-api/utils/utils.ts<method> generated url is correct (asserts method, URL, query params even if empty)<method> all response body properties (asserts request body even if empty, response body)<method> error 400 response<method> error 500 response<method> required response body properties (ONLY if WireMock mapping exists).toEqual() with whole objectsx-request-id and findWireMockRequest()Verification:
npm run build succeedsNO IMPLEMENTATION WITHOUT OPENAPI SPEC AND WIREMOCK MAPPINGS.
No exceptions. No guessing. No "I'll verify later."
The spec is the contract. Implementation must match the spec exactly. Tests require WireMock mappings to run.