Ever stood in front of your fridge, staring at random ingredients, wondering "What the heck can I make with leftover chicken, some bell peppers, and that lonely onion?" Well, I built an app for exactly that!
๐ฏ The Problem: Fridge Tetris & Recipe Roulette
We've all been there - you're hungry, you open the fridge, and it's like playing ingredient Tetris. You've got:
- Half a bell pepper (slightly wrinkled but still good!)
- Some chicken breast that expires tomorrow
- Random herbs you bought for that one recipe two weeks ago
- A can of tomatoes you forgot about
Instead of ordering takeout (again), I decided to build a smart Recipe Finder app that turns your random ingredients into actual meal suggestions!
๐ What We're Building
The Recipe Finder is a React-powered web app that:
- โจ Takes your ingredients as input
- ๐ Searches thousands of recipes via Spoonacular API
- ๐ฑ Shows beautiful recipe cards with images
- ๐ฏ Matches recipes based on what you actually have
Here's how the magic happens:
๐๏ธ Tech Stack & Architecture
Before diving into code, let's look at our simple but effective tech stack:
{
"frontend": "React 18 + Vite",
"styling": "Vanilla CSS with inline styles",
"api": "Spoonacular Recipe API",
"http": "Axios for API calls",
"dev_tools": "ESLint + Vite dev server"
}
๐ง Setting Up the Foundation
Let's start with the project structure. I used Vite because it's blazingly fast and perfect for React projects:
npm create vite@latest recipe-finder -- --template react
cd recipe-finder
npm install axios
The beauty of this setup? You get hot reload, optimized builds, and a development server that starts in milliseconds!
๐ณ The Core Recipe Logic
Here's where the magic happens. The main App.jsx
component handles all our recipe-finding logic:
import React, { useState } from "react";
import axios from "axios";
// API Configuration - keep your secrets safe!
const API_KEY = import.meta.env.VITE_SPOONACULAR_API_KEY;
const BASE_URL = "https://api.spoonacular.com/recipes/findByIngredients";
function App() {
const [ingredientList, setIngredientList] = useState("");
const [recipeList, setRecipeList] = useState([]);
const [errorMessage, setErrorMessage] = useState("");
const fetchRecipes = async () => {
if (!ingredientList.trim()) {
setErrorMessage("Please enter some ingredients.");
return;
}
setErrorMessage("");
setRecipeList([]);
try {
const { data } = await axios.get(BASE_URL, {
params: {
ingredients: ingredientList,
number: 5,
apiKey: API_KEY,
},
});
setRecipeList(data || []);
} catch (error) {
console.error("Error fetching recipes:", error);
setErrorMessage("Failed to fetch recipes. Please try again.");
}
};
return (
<div style={{ padding: "20px", maxWidth: "600px", margin: "0 auto" }}>
<h1>Recipe Finder</h1>
<textarea
rows="5"
value={ingredientList}
onChange={(e) => setIngredientList(e.target.value)}
placeholder="Enter your ingredients (comma-separated)..."
style={{ width: "100%", marginBottom: "10px", padding: "10px" }}
/>
<button onClick={fetchRecipes}>Find Recipes</button>
{errorMessage && <p style={{ color: "red" }}>{errorMessage}</p>}
<RecipeList recipes={recipeList} />
</div>
);
}
๐จ Creating Beautiful Recipe Cards
The recipe display component is where the app really shines. Each recipe gets its own card with an image and title:
function RecipeList({ recipes }) {
if (recipes.length === 0) return null;
return (
<div style={{ marginTop: "20px" }}>
<h3>Suggested Recipes:</h3>
<div style={{
display: "flex",
flexWrap: "wrap",
gap: "20px",
listStyle: "none",
padding: 0
}}>
{recipes.map((recipe, index) => (
<div key={index} style={{
textAlign: "center",
width: "200px",
padding: "10px",
border: "1px solid #ddd",
borderRadius: "8px",
boxShadow: "0 2px 4px rgba(0,0,0,0.1)"
}}>
<img
src={recipe.image}
alt={recipe.title}
style={{
width: "100%",
height: "150px",
objectFit: "cover",
borderRadius: "4px",
marginBottom: "8px"
}}
/>
<strong>{recipe.title}</strong>
</div>
))}
</div>
</div>
);
}
๐ Environment Variables & Security
Security first! Never expose your API keys. I use Vite's environment variable system:
# .env file
VITE_SPOONACULAR_API_KEY=your_actual_api_key_here
// In your app
const API_KEY = import.meta.env.VITE_SPOONACULAR_API_KEY;
Pro tip: Add .env
to your .gitignore
file! Nothing ruins your day like accidentally pushing API keys to GitHub ๐
๐ The Spoonacular API Magic
The Spoonacular API is the secret sauce here. Their findByIngredients
endpoint is perfect for our use case:
const apiResponse = await axios.get(BASE_URL, {
params: {
ingredients: "chicken,tomatoes,onions", // comma-separated
number: 5, // limit results
apiKey: API_KEY,
},
});
The API returns an array of recipes with:
- ๐ท Beautiful food images
- ๐ท๏ธ Recipe titles
- ๐ฅ Which ingredients were used
- ๐ How many ingredients were missing
๐ Running the App
Getting this beauty running is super simple:
# Install dependencies
npm install
# Start the dev server
npm run dev
# Build for production
npm run build
Then open your browser to http://localhost:5173
and start discovering recipes!
๐ก Cool Features & Future Enhancements
What makes this app special:
โจ Current Features:
- Instant Search - Type ingredients, get recipes immediately
- Visual Results - Beautiful recipe cards with images
- Error Handling - Graceful failures with helpful messages
- Responsive Design - Works on desktop and mobile
๐ฎ Future Improvements:
- ๐ฅ Dietary filters (vegetarian, vegan, gluten-free)
- โญ Recipe ratings and reviews
- ๐ Shopping list generation for missing ingredients
- ๐ฑ Mobile app version
- ๐ฝ๏ธ Meal planning features
๐ Performance & Best Practices
Here are some optimization techniques I used:
// Efficient state management
const [ingredientList, setIngredientList] = useState("");
const [recipeList, setRecipeList] = useState([]);
const [errorMessage, setErrorMessage] = useState("");
// Input validation before API calls
if (!ingredientList.trim()) {
setErrorMessage("Please enter some ingredients.");
return;
}
// Error handling with user-friendly messages
catch (error) {
console.error("Error fetching recipes:", error);
setErrorMessage("Failed to fetch recipes. Please try again.");
}
๐ฏ Key Learnings & Gotchas
Building this app taught me several valuable lessons:
- API Rate Limits - Spoonacular has daily limits, so implement caching for production
- Error Handling - Always assume the API might fail and handle it gracefully
- UX Matters - Loading states and error messages make users happy
- Keep It Simple - Sometimes vanilla CSS is better than heavy frameworks
๐ Try It Yourself!
Want to build your own Recipe Finder? Here's how:
- Get a Spoonacular API key (they have a free tier!)
- Clone the project: Recipe Finder on GitHub
-
Add your API key to the
.env
file - Start coding and make it your own!
๐ More AI-Powered Projects
This Recipe Finder is part of my Mini AI Projects collection, where I explore different APIs and AI services. Check out my other projects:
- ๐ผ๏ธ Image Captioning App - AI describes your photos
- ๐ฌ Sentiment Analysis Tool - Analyze text emotions
- ๐ค Personal AI Chatbot - Your own DialoGPT assistant
- ๐ Document Summarizer - BART-powered text summarization
๐ Conclusion
Building the Recipe Finder was an absolute blast! It solves a real problem (what to cook with random ingredients) while being simple enough to understand and extend.
The combination of React's reactivity, Vite's speed, and Spoonacular's rich API creates a powerful yet lightweight application. Whether you're a beginner learning React or an experienced developer looking for a fun weekend project, this recipe finder is a perfect starting point.
What's your favorite coding project that solves an everyday problem? Drop a comment below! ๐
Want to build your own AI-powered web app? I'd love to help! Reach out to me at landix.ninal@gmail.com and let's create something amazing together! ๐
Find the complete source code on GitHub and follow me for more AI/ML projects!
Top comments (0)