How to Build an App – Backend#
Laying Out the Framework#
Our project is a unit converter app that allows users to convert between different units in four categories: Length, Weight, Cooking, and Temperature. The app follows a separate frontend and backend architecture, which brings several advantages:
Separation of Concerns: By keeping the frontend and backend independent, each part can be developed, tested, and updated separately without breaking the other.
Scalability: This structure allows for easier scaling in the future. For example, if we want to expand the app to other platforms (web, desktop), we can reuse the backend without major changes.
Flexibility: Different technologies can be used for each part, allowing us to choose the best tools for each job.
For the backend, we chose Python with FastAPI. FastAPI is a modern, fast (high-performance) web framework for building APIs with Python. It is known for its simplicity, excellent performance, and automatic generation of API documentation.
For the frontend, we used React Native with Expo, which enables us to build native mobile applications for both Android and iOS using JavaScript and React. Expo simplifies the development process with pre-built tools and services, making it easier to test and deploy apps quickly.
We’ll dive deeper into both the backend and frontend setups later in this tutorial, but this framework gives us a strong, modular foundation to build a reliable, flexible, and user-friendly app.
Setting Up Your Environment#
To begin, we’ll set up the project structure and version control using Git and GitHub.
Create a GitHub Repository Start by creating a new repository on GitHub called
unit_converter
. This will help track your project’s progress and make collaboration easier.Clone the Repository Locally Open your terminal and run the following command to clone the repository to your local machine:
git clone https://github.com/your-username/unit_converter.git
Replace
your-username
with your actual GitHub username.Set Up the Backend Folder Inside the cloned repository, create a folder called
backend
. This folder will contain all the backend code for your project:cd unit_converter mkdir backend
This clean project structure keeps your backend organized and allows you to build the frontend separately. We’ll add the backend files and set up the FastAPI server in the next steps.
Building the Backend#
The backend for our unit converter app is built using Python and the FastAPI framework. The backend is responsible for performing the actual unit conversion calculations based on requests from the frontend.
Why FastAPI?
We chose FastAPI for several reasons:
High Performance: FastAPI is one of the fastest Python web frameworks, thanks to its asynchronous support and use of Python’s
async
features.Easy to Learn and Use: FastAPI has a simple, intuitive syntax that makes it accessible, even for developers new to building APIs.
Automatic API Documentation: FastAPI automatically generates interactive API docs using Swagger UI and ReDoc, which helps with testing and development.
Built-in Data Validation: FastAPI uses Python type hints and the powerful Pydantic library for validating request data, making the code more robust and less error-prone.
Other Backend Options
While FastAPI is a great choice for this project, there are other popular frameworks for building backends, depending on your needs:
Flask (Python): A lightweight framework that’s easy to get started with but lacks some features like built-in data validation and async support.
Django (Python): A full-featured framework with built-in admin tools, ideal for larger, more complex projects but potentially overkill for a simple API like this.
Express.js (JavaScript/Node.js): A popular backend framework for JavaScript developers, especially useful if you prefer to keep both frontend and backend in the same language.
For this project, FastAPI strikes the right balance between simplicity, performance, and ease of use, making it ideal for building a reliable, efficient API for our mobile app.
In the next section, we’ll walk through setting up FastAPI and writing the conversion logic.
Setting Up FastAPI#
Step 1: Create a Virtual Environment#
In your terminal, make sure you’re inside the backend
folder of your project. It’s good practice to use a virtual environment, which keeps your project’s dependencies isolated from your system-wide Python packages.
To create and activate a virtual environment, run the following commands:
python -m venv venv # Create a virtual environment named 'venv'
Activate the virtual environment:
Mac/Linux:
source venv/bin/activate
Windows:
venv\Scripts\activate
You should now see the environment activated, indicated by (venv)
at the start of your terminal prompt.
Step 2: Install FastAPI and Uvicorn#
With the virtual environment active, install FastAPI and Uvicorn (the ASGI server that runs your app):
pip install fastapi uvicorn
To save your project dependencies for later use, run:
pip freeze > requirements.txt
This creates a requirements.txt
file so others can install the same dependencies with:
pip install -r requirements.txt
Project Structure#
Step 1: Set Up File Structure#
Inside your backend
folder, set up the following folder structure for your project:
unit_converter/
├── backend/
│ └── app/
│ ├── __init__.py # Marks this folder as a Python package
│ ├── main.py # Entry point for the FastAPI application
│ ├── models.py # (Optional) For data models or request/response schemas
│ └── converters.py # Contains the unit conversion logic
├── requirements.txt # Lists project dependencies
The
app
folder contains all your backend code.main.py
is where you’ll set up the FastAPI routes.converters.py
will store your unit conversion functions.models.py
is useful for organizing request/response data structures.requirements.txt
keeps track of your project dependencies for easy setup.
This structure keeps your code organized and scalable as the project grows.
Step 2: Setting Up main.py
#
Inside your app
folder, open the main.py
file and add the following code:
from fastapi import FastAPI, HTTPException
from app.models import ConversionRequest
from app.converters import convert_units
app = FastAPI()
@app.post("/convert")
def convert(request: ConversionRequest):
print("Incoming request:", request)
try:
result = convert_units(request.value, request.from_unit, request.to_unit, request.conversion_type)
return {"result": result}
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
What This Code Does#
Import Required Modules
FastAPI
is the main framework for building your API.HTTPException
is used to handle errors and return appropriate HTTP status codes.ConversionRequest
is a data model that defines the expected structure of the incoming request (you’ll create this inmodels.py
).convert_units
is a function that performs the actual unit conversion logic (you’ll define this inconverters.py
).
Create the FastAPI App
app = FastAPI()
This creates an instance of your FastAPI application, which will handle incoming requests.
Define the /convert
Route
@app.post("/convert")
This defines a POST endpoint at /convert
. The client (in this case, the mobile app) will send conversion requests to this route.
Handle the Conversion Logic
The function accepts a request of type ConversionRequest
(more on this soon), which contains the necessary information for the conversion:
result = convert_units(request.value, request.from_unit, request.to_unit, request.conversion_type)
If the conversion succeeds, the API returns a JSON response with the result:
{"result": converted_value}
Error Handling
If invalid data is sent (e.g., unsupported units or conversion type), the code raises an HTTPException
with a 400 Bad Request
status:
raise HTTPException(status_code=400, detail=str(e))
This ensures the client gets a clear error message if the request is incorrect.
In the next step, we’ll define the ConversionRequest
model and build the actual conversion logic.
Step 3: Defining the Data Model in models.py
#
Inside your app
folder, open the models.py
file and add the following code:
from pydantic import BaseModel
class ConversionRequest(BaseModel):
value: float
from_unit: str
to_unit: str
conversion_type: str
What This Code Does#
Pydantic for Data Validation
We use the pydantic
library, which is built into FastAPI, to automatically validate and parse incoming request data.
Defining the Request Structure
The ConversionRequest
class inherits from BaseModel
, meaning FastAPI expects requests to follow this exact structure:
Field |
Type |
Description |
---|---|---|
|
float |
The numeric value the user wants to convert |
|
str |
The unit the value is currently in |
|
str |
The unit the value should be converted to |
|
str |
The type of conversion (e.g., “length”, “weight”, “cooking”, “temperature”) |
Example of what a valid request to your /convert
API looks like:
{
"value": 10,
"from_unit": "meters",
"to_unit": "feet",
"conversion_type": "length"
}
FastAPI automatically:
Parses this incoming JSON request
Converts the fields to the correct types
Returns helpful error messages if required fields are missing or the types are incorrect
This helps keep your API secure, predictable, and easy to work with.
Next, we’ll build the actual conversion logic inside converters.py
.
Step 4: Writing the Conversion Logic (converters.py
)#
Inside your app
folder, open the converters.py
file and add the following code:
conversion_data = {
"length": {
"inches": 1.0,
"cm": 2.54,
"feet": 1 / 12,
"meters": 0.0254
},
"weight": {
"grams": 1.0,
"kg": 0.001,
"pounds": 0.00220462,
"ounces": 0.035274
},
"cooking": {
"tsp": 1.0,
"tbsp": 0.333333,
"cups": 0.0208333,
"ml": 4.92892
}
}
This dictionary stores the conversion rates for different unit categories. The conversion system works by:
Defining a “base” unit for each category (
inches
for length,grams
for weight,tsp
for cooking).All other units are defined relative to that base.
Handling Temperature Conversions
Temperature conversions require special formulas because they are non-linear. Here’s the code:
def convert_temperature(value: float, from_unit: str, to_unit: str) -> float:
"""Handle temperature conversions with proper formulas"""
from_unit = from_unit.lower()
to_unit = to_unit.lower()
# Convert input to Celsius first
if from_unit == "celsius":
celsius_value = value
elif from_unit == "fahrenheit":
celsius_value = (value - 32) * 5/9
elif from_unit == "kelvin":
celsius_value = value - 273.15
else:
raise ValueError(f"Invalid temperature unit: {from_unit}")
# Convert from Celsius to target unit
if to_unit == "celsius":
result = celsius_value
elif to_unit == "fahrenheit":
result = (celsius_value * 9/5) + 32
elif to_unit == "kelvin":
result = celsius_value + 273.15
else:
raise ValueError(f"Invalid temperature unit: {to_unit}")
return round(result, 4)
How it works:
Converts the input temperature to Celsius as an intermediate step.
Then converts from Celsius to the target unit.
Raises an error for unsupported units.
Main Conversion Function
The function below handles both standard conversions and temperature:
def convert_units(value: float, from_unit: str, to_unit: str, conversion_type: str) -> float:
"""Main conversion function that handles all unit types"""
conversion_type = conversion_type.lower()
# Special handling for temperature
if conversion_type == "temperature":
return convert_temperature(value, from_unit, to_unit)
# Handle other conversions (length, weight, cooking)
units = conversion_data.get(conversion_type)
if not units:
raise ValueError(f"Invalid conversion type: {conversion_type}")
from_rate = units.get(from_unit.lower())
to_rate = units.get(to_unit.lower())
if from_rate is None or to_rate is None:
raise ValueError("Invalid units for selected conversion type")
result = (value * to_rate) / from_rate
return round(result, 4)
What This Function Does:#
Temperature Check
If the conversion type is "temperature"
, the function calls convert_temperature()
with the proper formulas.
Standard Unit Conversions
For other types (length
, weight
, cooking
):
The function looks up the conversion rates for the
from_unit
andto_unit
.Converts the value using:
result = (value * to_rate) / from_rate
Returns the result rounded to 4 decimal places.
Error Handling
The function raises a ValueError
if:
The conversion type is invalid
The units provided aren’t recognized
Next Steps: Connecting the Frontend#
The next step is to set up the frontend of the app to communicate with it.
Head over to the frontend project files where you’ll:
Configure the app to send conversion requests to the ngrok URL
Handle user input and display conversion results
Build the user interface with React Native and Expo
This will complete the flow from user input on the mobile app to processing on the backend and displaying results back to the user.
Acknowledgements#
By Meara Cox, Summer Internship, June 2025