Back to articles

From Zero to Production: Building a Full-Stack Application with React, TypeScript, and Serverless Functions

AuthorMajd Muhtaseb05/06/202512 minutes
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.