🪻 distributed transcription service thistle.dunkirk.sh
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: standardize API response formats

Convert all message-only responses to include success field for consistency:
- { message: "..." } → { success: true, message: "..." }

Standardized patterns:
- Success operations: { success: true }
- Success with message: { success: true, message: "..." }
- Success with data: { success: true, data: {...}, message?: "..." }
- Error responses: { error: "..." } (unchanged)
- Data responses: Direct objects like { user, jobs, classes } (unchanged)

Changes:
- Email verification success response
- Verification email sent response
- Verification code sent response
- Password reset link sent response
- Password reset success response

Added comprehensive test suite documenting API response standards.

💘 Generated with Crush

Assisted-by: Claude Sonnet 4.5 via Crush <crush@charm.land>

+142 -2
+6 -2
src/index.ts
··· 593 593 594 594 return Response.json( 595 595 { 596 + success: true, 596 597 message: "Email verified successfully", 597 598 email_verified: true, 598 599 user: { id: user.id, email: user.email }, ··· 640 641 }), 641 642 }); 642 643 643 - return Response.json({ message: "Verification email sent" }); 644 + return Response.json({ success: true, message: "Verification email sent" }); 644 645 } catch (error) { 645 646 return handleError(error); 646 647 } ··· 671 672 if (!user) { 672 673 // Don't reveal if user exists 673 674 return Response.json({ 675 + success: true, 674 676 message: 675 677 "If an account exists with that email, a verification code has been sent", 676 678 }); ··· 698 700 }); 699 701 700 702 return Response.json({ 703 + success: true, 701 704 message: "Verification code sent", 702 705 verification_code_sent_at: sentAt, 703 706 }); ··· 742 745 } 743 746 744 747 return Response.json({ 748 + success: true, 745 749 message: 746 750 "If an account exists with that email, a password reset link has been sent", 747 751 }); ··· 825 829 await updateUserPassword(userId, password); 826 830 consumePasswordResetToken(token); 827 831 828 - return Response.json({ message: "Password reset successfully" }); 832 + return Response.json({ success: true, message: "Password reset successfully" }); 829 833 } catch (error) { 830 834 console.error("[Email] Reset password error:", error); 831 835 return Response.json(
+136
src/lib/api-response-format.test.ts
··· 1 + import { describe, expect, test } from "bun:test"; 2 + 3 + /** 4 + * API Response Format Standards 5 + * 6 + * This test documents the standardized response formats across the API. 7 + * All endpoints should follow these patterns for consistency. 8 + */ 9 + 10 + describe("API Response Format Standards", () => { 11 + test("success responses should include success: true", () => { 12 + // Success-only responses (no data returned) 13 + const successOnly = { success: true }; 14 + expect(successOnly).toHaveProperty("success", true); 15 + 16 + // Success with message 17 + const successWithMessage = { 18 + success: true, 19 + message: "Operation completed successfully", 20 + }; 21 + expect(successWithMessage).toHaveProperty("success", true); 22 + expect(successWithMessage).toHaveProperty("message"); 23 + 24 + // Success with data 25 + const successWithData = { 26 + success: true, 27 + data: { id: 1, name: "Test" }, 28 + }; 29 + expect(successWithData).toHaveProperty("success", true); 30 + expect(successWithData).toHaveProperty("data"); 31 + }); 32 + 33 + test("error responses should use error field", () => { 34 + const errorResponse = { error: "Something went wrong" }; 35 + expect(errorResponse).toHaveProperty("error"); 36 + expect(typeof errorResponse.error).toBe("string"); 37 + }); 38 + 39 + test("data responses can return data directly", () => { 40 + // Direct data return (common pattern for GET endpoints) 41 + const userData = { 42 + user: { id: 1, email: "test@example.com" }, 43 + has_subscription: true, 44 + }; 45 + expect(userData).toHaveProperty("user"); 46 + 47 + // List responses 48 + const listData = { 49 + jobs: [{ id: "1" }, { id: "2" }], 50 + pagination: { limit: 50, hasMore: false, nextCursor: null }, 51 + }; 52 + expect(listData).toHaveProperty("jobs"); 53 + expect(listData).toHaveProperty("pagination"); 54 + }); 55 + 56 + test("message-only responses are converted to success+message", () => { 57 + // OLD (deprecated): { message: "..." } 58 + // NEW (standard): { success: true, message: "..." } 59 + 60 + const newFormat = { 61 + success: true, 62 + message: "Verification email sent", 63 + }; 64 + 65 + expect(newFormat).toHaveProperty("success", true); 66 + expect(newFormat).toHaveProperty("message"); 67 + }); 68 + }); 69 + 70 + describe("API Response Patterns", () => { 71 + test("authentication responses", () => { 72 + // Login success 73 + const login = { 74 + user: { id: 1, email: "test@example.com" }, 75 + email_verification_required: false, 76 + }; 77 + expect(login).toHaveProperty("user"); 78 + 79 + // Logout success 80 + const logout = { success: true }; 81 + expect(logout.success).toBe(true); 82 + 83 + // Email verified 84 + const verified = { 85 + success: true, 86 + message: "Email verified successfully", 87 + email_verified: true, 88 + user: { id: 1, email: "test@example.com" }, 89 + }; 90 + expect(verified.success).toBe(true); 91 + expect(verified).toHaveProperty("message"); 92 + }); 93 + 94 + test("CRUD operation responses", () => { 95 + // Create (returns created object) 96 + const created = { 97 + id: "123", 98 + name: "New Item", 99 + created_at: Date.now(), 100 + }; 101 + expect(created).toHaveProperty("id"); 102 + 103 + // Update (returns success) 104 + const updated = { success: true }; 105 + expect(updated.success).toBe(true); 106 + 107 + // Delete (returns success) 108 + const deleted = { success: true }; 109 + expect(deleted.success).toBe(true); 110 + 111 + // Get (returns data directly) 112 + const fetched = { 113 + id: "123", 114 + name: "Item", 115 + }; 116 + expect(fetched).toHaveProperty("id"); 117 + }); 118 + 119 + test("paginated list responses", () => { 120 + const paginatedList = { 121 + data: [{ id: "1" }, { id: "2" }], 122 + pagination: { 123 + limit: 50, 124 + hasMore: true, 125 + nextCursor: "MTczMjM5NjgwMHx0cmFucy0xMjM", 126 + }, 127 + }; 128 + 129 + expect(paginatedList).toHaveProperty("data"); 130 + expect(Array.isArray(paginatedList.data)).toBe(true); 131 + expect(paginatedList).toHaveProperty("pagination"); 132 + expect(paginatedList.pagination).toHaveProperty("limit"); 133 + expect(paginatedList.pagination).toHaveProperty("hasMore"); 134 + expect(paginatedList.pagination).toHaveProperty("nextCursor"); 135 + }); 136 + });