-
Couldn't load subscription status.
- Fork 48
refactor: extract and reuse helpers in api #82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
Claude finished @mkczarkowski's task —— View job Code Review Complete ✅Reviewing PR: refactor: extract and reuse helpers in api Tasks
SummaryThis is an excellent refactoring that significantly improves code quality and maintainability. The extraction of guards and utilities follows solid software engineering principles and eliminates substantial code duplication. The PR delivers on its promise of removing ~180 lines of boilerplate while maintaining (and in some cases improving) functionality. Strengths ✅
Areas for Improvement 🔍I've left 7 inline comments on specific files with detailed recommendations. Key issues: Critical Issues
Security Considerations
Code Quality Suggestions
Architecture AssessmentNew Infrastructure: The guard pattern is implemented correctly and follows the middleware composition pattern common in Node.js frameworks. The separation of concerns is clear:
Testing & Quality Assurance✅ All 185 tests passing This gives high confidence in the refactoring. RecommendationsBefore Merging:
Future Improvements:
Performance ImpactPositive: The refactoring should have minimal to no performance impact. The guard composition adds negligible overhead compared to the previous inline checks. Metrics
The net positive line count is expected and justified - you're building reusable infrastructure that will pay dividends as more routes are added. Verdict: ✅ Approve with Minor SuggestionsThis refactoring significantly improves the codebase. The identified issues are minor and mostly suggestions for further improvement. The PR can be merged after addressing the critical error handling issue in Great work! This sets an excellent foundation for future API development. |
| } | ||
| throw err; | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error Handling Issue: The catch block only handles SyntaxError for JSON parsing, but then re-throws other errors. This means any other error (e.g., network issues, captcha service errors) will bubble up as an unhandled exception and return a 500 error without proper error formatting.
Recommendation: Catch all errors and return a proper error response:
} catch (err) {
if (err instanceof SyntaxError) {
return validationError('Invalid request body');
}
console.error('Captcha verification error:', err);
return serverError('An unexpected error occurred during captcha verification');
}| requestorIp, | ||
| ); | ||
|
|
||
| if (!captchaResult.success) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Security Consideration: The error response exposes internal error codes from Cloudflare Turnstile. While this can be helpful for debugging, consider whether these error-codes should be exposed to end users in production.
Recommendation: Only include errorCodes in development mode:
if (!captchaResult.success) {
return errorResponse('Security verification failed. Please try again.', 400, {
type: 'captcha_failed',
...(import.meta.env.DEV && { errorCodes: captchaResult['error-codes'] }),
});
}| * @param data - The data to return | ||
| * @param status - HTTP status code (default: 200) | ||
| */ | ||
| export function successResponse<T = unknown>(data: T, status: number = 200): Response { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type Safety Issue: The successResponse function accepts any data type and doesn't validate the structure. This could lead to inconsistent API responses.
Recommendation: Consider constraining the type to match ApiSuccessResponse:
export function successResponse<T = unknown>(
data: ApiSuccessResponse<T> | T,
status: number = 200
): Response {
// If data doesn't have the expected shape, wrap it
const responseData = typeof data === 'object' && data !== null && ('data' in data || 'message' in data)
? data
: { data };
return new Response(JSON.stringify(responseData), {
status,
headers: { 'Content-Type': 'application/json' },
});
}This ensures all success responses have a consistent structure.
| * Extract the client IP address from request headers | ||
| * Checks Cloudflare's cf-connecting-ip header first | ||
| */ | ||
| export function getClientIp(request: Request): string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential Issue: getClientIp returns an empty string if the cf-connecting-ip header is not present. This could cause issues downstream if the calling code expects a valid IP or null.
Recommendation: Return null or a more explicit default:
export function getClientIp(request: Request): string | null {
return request.headers.get('cf-connecting-ip') || null;
}Also, consider adding fallback headers for non-Cloudflare environments (useful for local development):
export function getClientIp(request: Request): string | null {
return (
request.headers.get('cf-connecting-ip') ||
request.headers.get('x-forwarded-for')?.split(',')[0] ||
request.headers.get('x-real-ip') ||
null
);
}| const requestorIp = getClientIp(request); | ||
|
|
||
| // Check rate limit first | ||
| const { data: rateLimitResult, error: rateLimitCheckError } = await supabase.rpc( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Quality: Excellent error handling! The automatic verification email resend logic when login fails due to unconfirmed email is a great UX improvement. However, this logic is quite complex (60+ lines).
Recommendation: Consider extracting this into a reusable helper function like handleUnconfirmedEmail() in src/pages/api/utils/ to:
- Reduce complexity in the route handler
- Allow reuse if other endpoints need similar logic
- Make unit testing easier
|
✅ All checks have passed successfully!
Coverage reports have been uploaded as artifacts. |
Refactored auth API routes to use reusable guards and utilities, eliminating ~180
lines of duplicate code and establishing consistent patterns for feature flags,
captcha verification, and error responses.
Changes
New Infrastructure
etc.)
Refactored Routes
Example: Before & After
// Before: ~50 lines of boilerplate
export const POST: APIRoute = async ({ request, cookies }) => {
if (!isFeatureEnabled('auth')) { /* ... / }
const { email, captchaToken } = await request.json();
const captchaResult = await verifyCaptcha(/ ... /);
if (!captchaResult.success) { / ... */ }
// ... actual logic
};
// After: 3 lines of composition
export const POST: APIRoute = withFeatureFlag('auth',
withCaptcha(async ({ body }) => {
return successResponse({ message: 'Success' });
})
);
Benefits
handling
Testing