| name | platform-api-integration |
| description | Guide for discovering and integrating with Rubin Science Platform (RSP) APIs using OpenAPI specifications. Use this skill when working with Gafaelfawr authentication APIs (/auth/*), Times Square notebook APIs (/times-square/api/*), or other RSP services. Covers finding OpenAPI specs, using WebFetch to download specifications, creating TypeScript types from schemas, implementing SWR-based hooks, handling authentication patterns (CSRF tokens, credentials), and creating mock APIs for development. |
Platform API Integration
This skill covers discovering, exploring, and integrating with Rubin Science Platform (RSP) APIs using their OpenAPI specifications.
Quick Reference: OpenAPI Specifications
See api-registry.md for a complete list of RSP APIs and their OpenAPI specification URLs.
Primary APIs:
When to Use This Skill
Use this skill when you need to:
- Find API documentation for RSP services
- Discover available endpoints and their parameters
- Understand request/response schemas
- Implement new API integrations
- Create TypeScript types from API schemas
- Set up authentication for API calls
- Create mock APIs for local development
Discovering API Endpoints
Using WebFetch to Download OpenAPI Specs
When you need to explore an API, use the WebFetch tool to download the OpenAPI specification:
WebFetch({
url: 'https://gafaelfawr.lsst.io/_static/openapi.json',
prompt: 'Show me the available endpoints and their descriptions'
})
What to ask for:
- "Show me all endpoints for user token management"
- "What are the parameters for the create token endpoint?"
- "What does the user-info response schema look like?"
- "What authentication is required for this endpoint?"
Navigating OpenAPI Structure
OpenAPI specs are organized into these main sections:
Paths (/paths):
- Contains all available endpoints
- HTTP methods (GET, POST, DELETE, etc.)
- Path parameters (e.g.,
{username}, {token_key})
- Query parameters
- Request bodies
- Response schemas
Schemas (/components/schemas):
- Type definitions for request/response bodies
- Reusable data models
- Validation rules
Security (/components/securitySchemes):
- Authentication requirements
- OAuth scopes
- API keys
Finding Endpoint Details
To find information about a specific endpoint:
- Use WebFetch to download the OpenAPI spec
- Search for the path (e.g.,
/api/v1/user-info)
- Check the method (GET, POST, DELETE, etc.)
- Review parameters (path, query, body)
- Examine responses (200, 400, 401, etc.)
- Note authentication requirements
API-Specific Patterns
Gafaelfawr APIs (Authentication & Token Management)
Path Prefix: /auth/api/v1/
Common Endpoints:
GET /auth/api/v1/user-info - User profile and authentication status
GET /auth/api/v1/login - CSRF token and available scopes
GET /auth/api/v1/users/{username}/tokens - List user's tokens
POST /auth/api/v1/users/{username}/tokens - Create new token
DELETE /auth/api/v1/users/{username}/tokens/{key} - Delete token
GET /auth/api/v1/users/{username}/token-change-history - Token history with pagination
Authentication Pattern:
Gafaelfawr APIs use CSRF tokens for mutation operations (POST, DELETE):
- First, get the CSRF token from
/auth/api/v1/login
- Include it in mutation requests via
X-CSRF-Token header (DELETE) or x-csrf-token header (POST)
- Credentials are handled automatically via cookies
Example Implementations:
See existing hooks in the codebase:
apps/squareone/src/hooks/useUserInfo.ts - User profile fetching
apps/squareone/src/hooks/useLoginInfo.ts - CSRF token retrieval
apps/squareone/src/hooks/useUserTokens.ts - Token listing
apps/squareone/src/hooks/useTokenCreation.ts - Token creation with CSRF
apps/squareone/src/hooks/useDeleteToken.ts - Token deletion with CSRF
apps/squareone/src/hooks/useTokenChangeHistory.ts - Pagination example
Pagination Pattern:
Gafaelfawr uses cursor-based pagination with Link headers:
const linkHeader = response.headers.get('Link');
const totalCount = response.headers.get('X-Total-Count');
const { data, size, setSize, isValidating } = useSWRInfinite(
(pageIndex, previousPageData) => {
const cursor = previousPageData?.nextCursor;
return cursor ? `/api/endpoint?cursor=${cursor}` : '/api/endpoint';
}
);
Times Square APIs (Notebook Execution)
Path Prefix: /times-square/api/v1/
Common Endpoints:
GET /times-square/api/v1/pages - List all pages
GET /times-square/api/v1/pages/{page} - Get page metadata
GET /times-square/api/v1/pages/{page}/html - Get rendered HTML
GET /times-square/api/v1/pages/{page}/htmlstatus - Check rendering status
GET /times-square/api/v1/pages/{page}/htmlevents - SSE stream for real-time updates
Authentication Pattern:
Times Square APIs use cookie-based authentication (via Gafaelfawr):
- No explicit token needed in requests
- Credentials handled automatically
- No CSRF tokens required for GET requests
Parameter-based URLs:
Times Square APIs accept notebook parameters as URL query parameters:
function parameterizeUrl(
baseUrl: string,
parameters: Record<string, any>,
displaySettings: Record<string, any>
): string {
const url = new URL(baseUrl);
Object.entries(parameters).forEach(([key, value]) => {
url.searchParams.set(key, String(value));
});
Object.entries(displaySettings).forEach(([key, value]) => {
url.searchParams.set(key, String(value));
});
return url.toString();
}
Polling Pattern:
For checking notebook rendering status, use polling with SWR:
const { data, error } = useSWR<HtmlStatusData>(
htmlStatusUrl,
fetcher,
{
refreshInterval: 1000,
revalidateOnFocus: false,
}
);
Server-Sent Events (SSE):
For real-time updates, Times Square provides SSE endpoints:
- Connect to
/pages/{page}/htmlevents
- Receive
status events as notebook executes
- Context provider:
TimesSquareHtmlEventsContext
Example Implementations:
See existing implementations:
apps/squareone/src/hooks/useTimesSquarePage.ts - Page metadata
apps/squareone/src/components/TimesSquareNotebookViewer/useHtmlStatus.ts - Status polling
apps/squareone/src/contexts/TimesSquareUrlParametersContext.tsx - URL parameters
apps/squareone/src/contexts/TimesSquareHtmlEventsContext.tsx - SSE integration
Standard Integration Pattern
Step-by-Step: Adding a New API Endpoint
1. Find the Endpoint in OpenAPI Spec
Use WebFetch to download the OpenAPI spec and find:
- Endpoint path
- HTTP method
- Request parameters
- Response schema
- Authentication requirements
2. Create TypeScript Types
Extract the response schema from OpenAPI and create TypeScript types:
type UserInfo = {
username: string;
name?: string;
email?: string;
uid?: number;
gid?: number;
groups?: Group[];
};
type Group = {
id: number;
name: string;
};
3. Create a Custom Hook
Follow the SWR-based hook pattern. See hook-template.tsx for a complete template.
Basic pattern:
import useSWR from 'swr';
type UseApiHookResult = {
data: ResponseType | undefined;
isLoading: boolean;
error: Error | undefined;
mutate: () => void;
};
export function useApiHook(): UseApiHookResult {
const { data, error, isLoading, mutate } = useSWR<ResponseType>(
'/api/endpoint',
fetcher,
{
revalidateOnFocus: true,
revalidateOnReconnect: true,
dedupingInterval: 10000,
}
);
return {
data,
isLoading,
error,
mutate,
};
}
4. Handle Authentication
For Gafaelfawr mutations:
const { data: loginData } = useLoginInfo();
const csrfToken = loginData?.csrf;
const response = await fetch('/auth/api/v1/endpoint', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-csrf-token': csrfToken,
},
body: JSON.stringify(payload),
});
5. Implement Error Handling
Parse API errors and provide user-friendly messages:
type ApiError = {
detail?: string | Array<{ loc: string[]; msg: string; type: string }>;
message?: string;
};
function parseError(response: Response, data: ApiError): Error {
if (Array.isArray(data.detail)) {
const errors = data.detail.map(err => err.msg).join(', ');
return new Error(errors);
}
if (data.detail) {
return new Error(data.detail);
}
return new Error(`HTTP ${response.status}: ${response.statusText}`);
}
6. Create Mock API for Development
Create a mock endpoint in /pages/api/dev/:
import type { NextApiRequest, NextApiResponse } from 'next';
export default function handler(
req: NextApiRequest,
res: NextApiResponse
) {
res.status(200).json({
username: 'testuser',
name: 'Test User',
email: 'test@example.com',
});
}
7. Set Up Development Rewrites
Add to next.config.js:
async rewrites() {
return [
{
source: '/api/endpoint',
destination: '/api/dev/endpoint',
},
];
}
Development Workflow
Local Development with Mocks
For local development without backend services:
- Create mock endpoints in
/pages/api/dev/ matching OpenAPI schemas
- Set up Next.js rewrites to redirect API calls to mocks
- Use environment variables to toggle between real and mock APIs
Example rewrite configuration:
async rewrites() {
if (process.env.NODE_ENV === 'development') {
return [
{
source: '/auth/api/v1/user-info',
destination: '/api/dev/user-info',
},
{
source: '/times-square/api/v1/pages/:page',
destination: '/api/dev/times-square/v1/pages/:page',
},
];
}
return [];
}
Mock Data Best Practices
- Match OpenAPI schemas exactly - Use the same field names and types
- Include realistic data - Mimic production responses
- Test error cases - Create mock endpoints that return errors
- Use query parameters - Support filtering and pagination in mocks
- Maintain mock data files - Store mock data in
/src/lib/mocks/
Example mock data organization:
src/lib/mocks/
├── gafaelfawr/
│ ├── user-info.ts
│ ├── tokens.ts
│ └── token-history.ts
└── times-square/
├── pages.ts
└── page-metadata.ts
Common Patterns
SWR Configuration
Standard configuration for most endpoints:
{
revalidateOnFocus: true,
revalidateOnReconnect: true,
dedupingInterval: 10000,
}
For polling status endpoints:
{
refreshInterval: 1000,
revalidateOnFocus: false,
}
For static/rarely-changing data:
{
revalidateOnFocus: false,
revalidateOnReconnect: false,
revalidateIfStale: false,
}
Fetcher Function
Standard fetcher with error handling:
const fetcher = async (...args: Parameters<typeof fetch>) => {
const response = await fetch(...args);
if (!response.ok) {
const data = await response.json().catch(() => ({}));
throw parseError(response, data);
}
return response.json();
};
Hook Return Pattern
Consistent return types across all hooks:
return {
data,
isLoading,
error,
mutate,
};
TypeScript Best Practices
Type Definitions
Extract types from OpenAPI schemas:
type GafaelfawrUser = {
username: string;
name?: string;
email?: string;
uid?: number;
gid?: number;
groups?: GafaelfawrGroup[];
quota?: GafaelfawrQuota | null;
};
type GafaelfawrGroup = {
id: number;
name: string;
};
export type { GafaelfawrUser, GafaelfawrGroup };
Use discriminated unions for token types:
type TokenType =
| 'session'
| 'user'
| 'notebook'
| 'internal'
| 'service'
| 'oidc';
type TokenInfo = {
token_type: TokenType;
token: string;
username: string;
};
Error Types
Create specific error types for better error handling:
type TokenCreationError = {
type: 'validation' | 'network' | 'server';
message: string;
statusCode?: number;
details?: unknown;
};
Troubleshooting
OpenAPI Spec Not Loading
Problem: WebFetch cannot retrieve the OpenAPI specification.
Solutions:
- Verify the URL is correct (check api-registry.md)
- Check if the service is accessible
- Try accessing the URL directly in a browser
- Some services may require authentication to access OpenAPI specs
Type Mismatches
Problem: TypeScript types don't match actual API responses.
Solutions:
- Download the latest OpenAPI spec
- Check for API version differences
- Verify the endpoint path is correct
- Log actual responses during development
CSRF Token Errors
Problem: Gafaelfawr mutations fail with 403 errors.
Solutions:
- Ensure you're calling
useLoginInfo() to get the CSRF token
- Verify the CSRF token is included in request headers
- Check header name:
X-CSRF-Token for DELETE, x-csrf-token for POST
- Ensure cookies are being sent with requests
Mock API Not Being Used
Problem: Real API is called instead of mock in development.
Solutions:
- Check
next.config.js rewrites configuration
- Verify
NODE_ENV === 'development'
- Ensure mock endpoint path matches the rewrite destination
- Restart the dev server after config changes
Related Skills
- data-fetching-patterns - SWR patterns, custom hooks, error handling
- times-square-integration - Times Square specific patterns and contexts
- testing-infrastructure - Testing API hooks and mocks
Related Files
/pages/api/dev/ - Mock API endpoints for development
apps/squareone/src/hooks/ - Existing API hook implementations
apps/squareone/next.config.js - Next.js rewrite configuration
packages/squared/src/hooks/ - Shared API hooks
Additional Resources
OpenAPI Specifications:
Related Documentation: