Building a Serverless Profit/Loss Calculator with AWS Lambda, AWS API Gateway and React
Table of contents
Project Architecture
Our application follows a serverless architecture:
Frontend: React application hosted on Netlify
Backend: AWS Lambda function written in Python
API: AWS API Gateway to expose our Lambda function
Version Control: GitLab repository
Hosting: Netlify (frontend), AWS (backend)
This architecture allows for scalability, cost-effectiveness, and ease of maintenance.
Link to our Github Codebase
Setting Up the Backend
Let's start by creating our AWS Lambda function:
AWS Lambda Setup (Console)
Open the AWS Lambda console
Click "Create function"
Choose "Author from scratch"
Enter a function name (e.g., "profit-loss-calculator")
Select Python 3.8 (or later) as the runtime
Click "Create function"
- In the function code section, paste the following Python code:
import json
def calculate_profit_loss(revenue, costs):
profit_loss = revenue - costs
return profit_loss
def lambda_handler(event, context):
try:
# Parse input from the event
body = json.loads(event['body'])
revenue = float(body['revenue'])
costs = float(body['costs'])
# Calculate profit/loss
profit_loss = calculate_profit_loss(revenue, costs)
# Prepare the response
response = {
'profit_loss': profit_loss,
'message': 'Profit' if profit_loss > 0 else 'Loss' if profit_loss < 0 else 'Break-even'
}
return {
'statusCode': 200,
'body': json.dumps(response),
'headers': {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*' # Enable CORS for all origins
}
}
except Exception as e:
return {
'statusCode': 400,
'body': json.dumps({'error': str(e)}),
'headers': {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
}
Click "Deploy" to save changes
API Gateway Setup (Console)
Open the API Gateway console
Click "Create API"
Choose "REST API" and click "Build"
Enter an API name (e.g., "Profit-Loss-API")
Click "Create API"
[Placeholder for screenshot: API Gateway creation page]
Click "Create Resource"
Enter a resource name (e.g., "calculate")
Click "Create Resource"
With the new resource selected, click "Create Method"
Select "POST" from the dropdown and click the checkmark
Set Integration type to "Lambda Function"
Select your Lambda function and click "Save"
Developing the Frontend
Now, let's create our React frontend:
npx create-react-app profit-loss-calculator
cd profit-loss-calculator
Replace the contents of src/App.js
and also create FinancialModel.js Component:
App.js
import React from 'react';
import FinancialModel from './FinancialModel';
function App() {
return (
<div className="App">
<FinancialModel />
</div>
);
}
export default App;
FinancialModel.js Component
import React, { useState } from 'react';
const FinancialModel = () => {
const [revenue, setRevenue] = useState('');
const [costs, setCosts] = useState('');
const [result, setResult] = useState(null);
const [error, setError] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
setError('');
setResult(null);
try {
const response = await fetch('YOUR_API_GATEWAT_URL"), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ revenue: parseFloat(revenue), costs: parseFloat(costs) }),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setResult(data);
} catch (error) {
console.error('Fetch error:', error);
if (error.message.includes('CORS')) {
setError('CORS error: The server is not allowing this request. Please check CORS configuration.');
} else {
setError(`An error occurred: ${error.message}. Please try again.`);
}
}
};
return (
<div style={{ maxWidth: '400px', margin: '0 auto', padding: '20px' }}>
<h2 style={{ textAlign: 'center' }}>Financial Model Calculator</h2>
<form onSubmit={handleSubmit} style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
<div>
<label htmlFor="revenue">Revenue</label>
<input
id="revenue"
type="number"
value={revenue}
onChange={(e) => setRevenue(e.target.value)}
required
placeholder="Enter revenue"
style={{ width: '100%', padding: '5px' }}
/>
</div>
<div>
<label htmlFor="costs">Costs</label>
<input
id="costs"
type="number"
value={costs}
onChange={(e) => setCosts(e.target.value)}
required
placeholder="Enter costs"
style={{ width: '100%', padding: '5px' }}
/>
</div>
<button type="submit" style={{ padding: '10px', backgroundColor: '#007bff', color: 'white', border: 'none', cursor: 'pointer' }}>
Calculate
</button>
</form>
{error && (
<div style={{ marginTop: '10px', padding: '10px', backgroundColor: '#ffcccc', color: '#ff0000' }}>
{error}
</div>
)}
{result && (
<div style={{ marginTop: '10px' }}>
<h3>Result:</h3>
<p>Profit/Loss: ${result.profit_loss.toFixed(2)}</p>
<p>Status: {result.message}</p>
</div>
)}
</div>
);
};
export default FinancialModel;
Version Control with GitLab
To set up version control:
Create a new project in GitLab
Follow the instructions to push an existing folder:
cd existing_folder
git init
git remote add origin git@gitlab.com:your-username/profit-loss-calculator.git
git add .
git commit -m "Initial commit"
git push -u origin master
Deploying the Application
Backend Deployment
The backend is automatically deployed when you create and update your Lambda function and API Gateway.
Frontend Deployment with Netlify
Log in to Netlify
Click "New site from Git"
Choose GitLab and select your repository
Configure build settings:
Click "Deploy site"
After deployment, Netlify will provide a URL for your site.
Testing and Troubleshooting
Common issues and solutions:
CORS errors: Ensure API Gateway and Lambda both have CORS enabled
API Gateway integration errors: Check Lambda function permissions
React build errors: Verify all dependencies are correctly installed
Conclusion
We've successfully built a serverless profit/loss calculator using React, AWS Lambda, and API Gateway. This architecture provides a scalable and cost-effective solution.
Future improvements could include:
Adding more complex financial calculations
Implementing user authentication
Storing calculation history in a database