Building a React CRUD App with AWS API Gateway
Context: Personal React + AWS API Gateway prototype (private repo). Built to practice CRUD flows, optimistic UI, and serverless deploys. No production users.
AI assist: ChatGPT/Copilot scaffolded some components and Lambda handlers. Prompt logs live in the repo so it’s clear what code I edited.
Status: Demo runs on Vercel (frontend) + AWS API Gateway/Lambda/DynamoDB (backend). Auth, uploads, and Terraform modules are still TODOs.
Reality snapshot
- Frontend: React 18 + Vite, controlled forms, modals, context for auth state, optimistic updates. Hosted on Vercel.
- Backend: AWS API Gateway → Lambda (Node 20) → DynamoDB. API keys + throttling guard the endpoints.
- External data: Jikan API provides trending anime metadata. Cached per session to avoid hitting rate limits.
- Limitations: Auth is mocked, backend cold starts add ~2 s sometimes, and the repo is private until I scrub secrets.
Architecture
ReactJSMobileApp/├── src/│ ├── App.jsx│ ├── api.js│ ├── components/│ └── hooks/useFetch.js├── amplify/ (legacy)├── lambda/│ ├── createCharacter.js│ ├── listCharacters.js│ ├── updateCharacter.js│ └── deleteCharacter.js└── vercel.json
vercel.jsonproxies/api/*requests to API Gateway, injecting the API key server-side so the browser never sees it.- Lambda functions share a thin validation layer and log request IDs for tracing.
Client flow highlights
Fetch & cache characters
useEffect(() => {let active = true;(async () => {setLoading(true);try {const { data } = await api.get("/api/characters");if (active) setCharacters(data);} catch (error) {if (active) setError("Unable to load characters right now.");} finally {if (active) setLoading(false);}})();return () => {active = false;};}, []);
- Guards prevent state updates after unmount. Errors bubble into a toast + log entry.
Optimistic updates
const handleUpdate = async (character) => {const snapshot = characters;setCharacters((prev) =>prev.map((item) => (item.id === character.id ? character : item)));try {await api.put(`/api/characters/${character.id}`, character);} catch {setError("Could not save changes. Reverting.");setCharacters(snapshot);}};
- Keeps the UI responsive even when API Gateway cold starts. Rollback path restores prior state if Lambda fails.
Filtering with memoized selectors
const filteredCharacters = useMemo(() => {if (selectedCategory === "all") return characters;return characters.filter((character) => {const category = character.category?.toLowerCase();const role = character.role?.toLowerCase();return category === selectedCategory || role === selectedCategory;});}, [characters, selectedCategory]);
- Prevents unnecessary renders when the dataset grows.
Deployment + security notes
- Vercel Routes proxy requests to API Gateway, injecting
x-api-key. Rate limits + throttles configured in API Gateway. - Lambda validates payloads with
ajv, normalizes responses, and logs structured JSON. - Terraform/SAM scripts exist but aren’t production-ready—still manual deployments via
sam deploy. - Environment variables live in Vercel secrets + AWS Parameter Store.
Challenges & fixes
- CORS headaches: Solved by proxying through Vercel and enabling CORS on API Gateway.
- Slow cold starts: Mitigated with optimistic UI + skeleton loaders. Future improvement = provisioned concurrency or scheduled warmers.
- Schema drift: Added JSON schema validation + Jest tests so the frontend can’t send malformed payloads.
- Rate limiting: Respect
Retry-Afterfrom Jikan; UI shows a friendly message and caches the last successful response.
TODO list
- Add Cognito auth + user-specific lists.
- Upload images to S3 instead of relying on remote URLs.
- Finish Terraform modules (VPC, API Gateway, DynamoDB) and publish them.
- Write Playwright tests covering the top flows.
- Sanitize the repo so I can make it public without leaking secrets.
Links
- Live demo: https://cruddemo-one.vercel.app/ (backend sleeps when unused; expect a short delay).
- Repo (request access): https://github.com/BradleyMatera/ReactJSMobileApp
- Prompt log + runbook:
docs/folder inside the repo describes every feature, limitation, and AI assist.