From Zero to Production: Building a Full-Stack Application with React, TypeScript, and Serverless Functions
Introduction
Building modern web applications often involves juggling multiple technologies. This article demonstrates how to create a simple yet robust full-stack application using React for the frontend, TypeScript for type safety, and serverless functions (specifically AWS Lambda) for the backend. This approach provides scalability, cost-effectiveness, and a streamlined development experience.
Setting Up the React Frontend
We'll start with a basic React application bootstrapped with Create React App and configured for TypeScript.
npx create-react-app my-app --template typescript
cd my-app
Next, let's create a simple component to fetch data from our serverless backend.
// src/components/DataDisplay.tsx
import React, { useState, useEffect } from 'react';
interface Data {
message: string;
}
const DataDisplay: React.FC = () => {
const [data, setData] = useState<Data | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('/.netlify/functions/hello'); // Replace with your function URL
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
setData(json);
} catch (e) {
setError((e as Error).message);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return (
<div>
{data && <p>Message from server: {data.message}</p>}
</div>
);
};
export default DataDisplay;
Creating the Serverless Backend (AWS Lambda)
For our backend, we'll use AWS Lambda and the Serverless Framework to create a simple "Hello World" function. First, you need an AWS account and the Serverless Framework installed.
npm install -g serverless
Create a serverless.yml
file in your project root (outside the my-app
directory):
# serverless.yml
service: my-serverless-app
provider:
name: aws
runtime: nodejs18.x
region: us-east-1 # Replace with your preferred region
iamRoleStatements:
- Effect: "Allow"
Action:
- "dynamodb:GetItem"
- "dynamodb:PutItem" #example action. remove if not required
Resource: "arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/YOUR_TABLE_NAME" # Example Resource. Replace with your DynamoDB table ARN
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
cors: true
Now, create a handler.js
file:
// handler.js
exports.hello = async (event) => {
return {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": "*", // Required for CORS support to work
"Access-Control-Allow-Credentials": true, // Required for cookies, authorization headers with HTTPS
},
body: JSON.stringify({
message: "Hello from your serverless function!",
}),
};
};
Deploy your function using the Serverless Framework:
serverless deploy
Note the URL of the deployed function, you will need it for development if you aren't using a proxy during development.
Integrating Frontend and Backend
Update your React component's fetch
call to point to the API Gateway endpoint created by Serverless. If using netlify dev (or similar), use /.netlify/functions/hello
. If not, use the AWS generated URL for development.
Deployment
You can deploy the React frontend using Netlify, Vercel, or similar platforms. The Serverless Framework handles the backend deployment. Remember to configure environment variables for your API endpoint URLs.
Conclusion
This article provides a foundation for building full-stack applications with React, TypeScript, and serverless functions. This approach offers scalability, cost-effectiveness, and a simplified development workflow. Explore further by adding databases, authentication, and more complex business logic to your serverless functions. Remember to adjust the IAM role according to your needs.