Full-Stack Web Application Example
🔧 Configuration
⚡ Setup Guide
To run the examples on this page, you need a RESTHeart instance.
Option 1: Use RESTHeart Cloud (Recommended)
The fastest way to get started is with RESTHeart Cloud. Create a free service in minutes:
-
Sign up at cloud.restheart.com
-
Create a free API service
-
Set up your root user following the Root User Setup guide
-
Use the configuration panel above to set your service URL and credentials
Tip
|
All code examples on this page will automatically use your configured RESTHeart Cloud credentials. |
Option 2: Run RESTHeart Locally
If you prefer local development, follow the Setup Guide to install RESTHeart on your machine.
Note
|
Local instances run at http://localhost:8080 with default credentials admin:secret
|
Build a complete full-stack web application with RESTHeart Cloud! This example demonstrates how to create both the backend API and a production-ready frontend using Vue.js, React, or Angular.
Tip
|
This example combines:
You’ll have a working full-stack application in under 10 minutes! |
What You’ll Build
A complete e-commerce product catalog application featuring:
-
Product Management - Create, read, update, and delete products
-
Search Functionality - Real-time product search by name
-
Price Filtering - Interactive price range filters
-
Category Browsing - Browse products by category
-
Responsive Design - Works on desktop, tablet, and mobile
-
RESTful API - Fully functional REST API with MongoDB
-
Authentication - Secure access control with ACL
Part 1: Backend Setup
Step 1: Create Collections
First, create the collections for products, categories, and inventory:
cURL
# Create collections
curl -i -X PUT [RESTHEART-URL]/products \
-H "Authorization: Basic [BASIC-AUTH]"
curl -i -X PUT [RESTHEART-URL]/categories \
-H "Authorization: Basic [BASIC-AUTH]"
curl -i -X PUT [RESTHEART-URL]/inventory \
-H "Authorization: Basic [BASIC-AUTH]"
# Create permission for unauthenticated read access to products
curl -i -X POST [RESTHEART-URL]/acl \
-H "Authorization: Basic [BASIC-AUTH]" -H "Content-Type: application/json" \
-d '{
"_id": "allCanGetProducts",
"roles": ["$unauthenticated"],
"predicate": "path(/products) and method(GET)",
"priority": 100
}'
HTTPie
# Create collections
http PUT [RESTHEART-URL]/products \
Authorization:"Basic [BASIC-AUTH]"
http PUT [RESTHEART-URL]/categories \
Authorization:"Basic [BASIC-AUTH]"
http PUT [RESTHEART-URL]/inventory \
Authorization:"Basic [BASIC-AUTH]"
# Create permission for unauthenticated read access to products
http POST [RESTHEART-URL]/acl \
Authorization:"Basic [BASIC-AUTH]" \
Content-Type:application/json \
_id="allCanGetProducts" \
roles:='["$unauthenticated"]' \
predicate="path(/products) and method(GET)" \
priority:=100
JavaScript
// Create collections
const createCollections = async () => {
const headers = {
'Authorization': 'Basic [BASIC-AUTH]'
};
fetch('[RESTHEART-URL]/products', {
method: 'PUT',
headers
})
.then(response => {
if (response.ok) {
console.log('Products collection created successfully');
} else {
console.error('Failed to create products collection:', response.status);
}
})
.catch(error => console.error('Error:', error));
fetch('[RESTHEART-URL]/categories', {
method: 'PUT',
headers
})
.then(response => {
if (response.ok) {
console.log('Categories collection created successfully');
} else {
console.error('Failed to create categories collection:', response.status);
}
})
.catch(error => console.error('Error:', error));
fetch('[RESTHEART-URL]/inventory', {
method: 'PUT',
headers
})
.then(response => {
if (response.ok) {
console.log('Inventory collection created successfully');
} else {
console.error('Failed to create inventory collection:', response.status);
}
})
.catch(error => console.error('Error:', error));
};
// Create permission for unauthenticated read access to products
const createProductsReadPermission = () => {
fetch('[RESTHEART-URL]/acl', {
method: 'POST',
headers: {
'Authorization': 'Basic [BASIC-AUTH]',
'Content-Type': 'application/json'
},
body: JSON.stringify({
_id: "allCanGetProducts",
roles: ["$unauthenticated"],
predicate: "path(/products) and method(GET)",
priority: 100
})
})
.then(response => {
if (response.ok) {
console.log('Products read permission created successfully');
} else {
console.error('Failed to create products read permission:', response.status);
}
})
.catch(error => console.error('Error:', error));
};
// Execute
createCollections();
createProductsReadPermission();
Step 2: Add Sample Data
Instead of manually creating each product, you can download sample data files and import them to your instance.
First, download the sample data files:
Download Sample Data
# Download categories
curl -o categories.json https://restheart.org/assets/categories.json
# Download products
curl -o products.json https://restheart.org/assets/products.json
Now import the data to your RESTHeart instance:
cURL
# Import categories
curl -X POST [RESTHEART-URL]/categories \
-H "Authorization: Basic [BASIC-AUTH]" \
-H "Content-Type: application/json" \
-d @categories.json
# Import products
curl -X POST [RESTHEART-URL]/products \
-H "Authorization: Basic [BASIC-AUTH]" \
-H "Content-Type: application/json" \
-d @products.json
HTTPie
# Import categories
http POST [RESTHEART-URL]/categories \
Authorization:"Basic [BASIC-AUTH]" \
Content-Type:application/json < categories.json
# Import products
http POST [RESTHEART-URL]/products \
Authorization:"Basic [BASIC-AUTH]" \
Content-Type:application/json < products.json
JavaScript
const fs = require('fs');
// Read and import categories
const importCategories = async () => {
try {
const categories = JSON.parse(fs.readFileSync('categories.json', 'utf8'));
const response = await fetch('[RESTHEART-URL]/categories', {
method: 'POST',
headers: {
'Authorization': 'Basic [BASIC-AUTH]',
'Content-Type': 'application/json'
},
body: JSON.stringify(categories)
});
if (response.ok) {
console.log('Categories imported successfully');
} else {
console.error('Failed to import categories:', response.status);
}
} catch (error) {
console.error('Error importing categories:', error);
}
};
// Read and import products
const importProducts = async () => {
try {
const products = JSON.parse(fs.readFileSync('products.json', 'utf8'));
const response = await fetch('[RESTHEART-URL]/products', {
method: 'POST',
headers: {
'Authorization': 'Basic [BASIC-AUTH]',
'Content-Type': 'application/json'
},
body: JSON.stringify(products)
});
if (response.ok) {
console.log('Products imported successfully');
} else {
console.error('Failed to import products:', response.status);
}
} catch (error) {
console.error('Error importing products:', error);
}
};
// Execute imports
(async () => {
await importCategories();
await importProducts();
console.log('Data import completed!');
})();
Step 3: Test Your API
Test the API endpoints to make sure everything is working:
cURL
# Search products by name
curl -i "[RESTHEART-URL]/products" \
-H "Authorization: Basic [BASIC-AUTH]" \
-G --data-urlencode "filter={'name':{'$regex':'headphones','$options':'i'}}"
# Filter by price range
curl "[RESTHEART-URL]/products" \
-H "Authorization: Basic [BASIC-AUTH]" \
-G --data-urlencode "filter={'price':{'$gte':50,'$lte':150}}"
# Get products with low inventory
curl "[RESTHEART-URL]/products" \
-H "Authorization: Basic [BASIC-AUTH]" \
-G --data-urlencode "filter={'quantity':{'$lt':10}}"
# Category-based filtering with sorting
curl "[RESTHEART-URL]/products" \
-H "Authorization: Basic [BASIC-AUTH]" \
-G --data-urlencode "filter={'category':'electronics'}" \
-G --data-urlencode "sort={'price':1}"
HTTPie
# Search products by name
http GET [RESTHEART-URL]/products \
Authorization:"Basic [BASIC-AUTH]" \
filter=="{'name':{\$regex:'headphones',\$options:'i'}}"
# Filter by price range
http GET [RESTHEART-URL]/products \
Authorization:"Basic [BASIC-AUTH]" \
filter=="{'price':{\$gte:50,\$lte:150}}"
# Get products with low inventory
http GET [RESTHEART-URL]/products \
Authorization:"Basic [BASIC-AUTH]" \
filter=="{'quantity':{\$lt:10}}"
# Category-based filtering with sorting
http GET [RESTHEART-URL]/products \
Authorization:"Basic [BASIC-AUTH]" \
filter=="{'category':'electronics'}" sort=="{price:1}"
JavaScript
// Search products by name
const searchByName = () => {
const filter = encodeURIComponent("{'name':{\$regex:'headphones',\$options:'i'}}");
fetch(`[RESTHEART-URL]/products?filter=${filter}`, {
headers: {
'Authorization': 'Basic [BASIC-AUTH]'
}
})
.then(response => response.json())
.then(data => {
console.log('Search results:', data);
})
.catch(error => console.error('Error:', error));
};
// Filter by price range
const filterByPriceRange = () => {
const filter = encodeURIComponent("{'price':{\$gte:50,\$lte:150}}");
fetch(`[RESTHEART-URL]/products?filter=${filter}`, {
headers: {
'Authorization': 'Basic [BASIC-AUTH]'
}
})
.then(response => response.json())
.then(data => {
console.log('Price range results:', data);
})
.catch(error => console.error('Error:', error));
};
// Get products with low inventory
const getLowInventory = () => {
const filter = encodeURIComponent("{'quantity':{\$lt:10}}");
fetch(`[RESTHEART-URL]/products?filter=${filter}`, {
headers: {
'Authorization': 'Basic [BASIC-AUTH]'
}
})
.then(response => response.json())
.then(data => {
console.log('Low inventory products:', data);
})
.catch(error => console.error('Error:', error));
};
// Category-based filtering with sorting
const filterByCategory = () => {
const filter = encodeURIComponent("{'category':'electronics'}");
const sort = encodeURIComponent("{price:1}");
fetch(`[RESTHEART-URL]/products?filter=${filter}&sort=${sort}`, {
headers: {
'Authorization': 'Basic [BASIC-AUTH]'
}
})
.then(response => response.json())
.then(data => {
console.log('Category results:', data);
})
.catch(error => console.error('Error:', error));
};
// Execute
searchByName();
filterByPriceRange();
getLowInventory();
filterByCategory();
Part 2: Frontend Setup
Now that your backend is ready, let’s build the frontend! We’ve created three complete implementations using modern JavaScript frameworks.
Choose Your Framework
All three frontend examples are available in our GitHub repository: restheart-cloud-examples
Each implementation is a complete single-page application featuring:
-
Product search by name - Real-time search functionality
-
Price range filtering - Interactive price filters
-
Category filtering - Browse products by category
-
Real-time updates - Live data from RESTHeart Cloud
-
Responsive design - Works on desktop, tablet, and mobile
-
Production-ready code - Best practices for each framework
Getting Started with the Frontend
1. Clone the Repository
git clone https://github.com/SoftInstigate/restheart-cloud-examples.git
cd restheart-cloud-examples
2. Choose Your Framework
# For Vue.js
cd vue-product-search
# OR for React
cd react-product-search
# OR for Angular
cd angular-product-search
3. Configure Your RESTHeart Cloud Instance
For Vue.js and React:
cp .env.example .env
# Edit .env and set VITE_RESTHEART_URL to your RESTHeart Cloud instance URL
For Angular:
# Edit src/environments/environment.ts and set restHeartUrl to your instance URL
4. Install Dependencies and Run
npm install
npm run dev # For Vue.js and React
npm start # For Angular
Note
|
Make sure you’ve completed the backend setup steps above, including:
Without these steps, the frontend applications won’t be able to fetch data from your RESTHeart Cloud instance. |
Learn More
-
More Backend Examples - Explore additional use cases
-
Users and Permissions - Deep dive into ACL
-
RESTHeart Documentation - Full documentation
-
GitHub Examples - Source code and more examples
Troubleshooting
Frontend Can’t Connect to Backend
-
Verify your RESTHeart URL is correct in the environment configuration
-
Check that the ACL permission for unauthenticated access is created
-
Ensure your RESTHeart Cloud instance is running
-
Check browser console for CORS errors
No Products Showing
-
Verify you’ve added sample data using the backend setup steps
-
Check the products collection exists:
curl [RESTHEART-URL]/products
-
Verify the ACL allows unauthenticated GET requests to /products
Search/Filter Not Working
-
Check that your MongoDB queries are properly formatted
-
Verify the filter parameters are correctly URL-encoded
-
Test the API endpoints directly with cURL or HTTPie
-
Check for JavaScript errors in the browser console
Support
Need help? Here are some resources: