Create a Project - Express.js -API
API Basics: REST vs GraphQL
✅ HTTP Methods & API Calls
✅ Authentication & Security (OAuth, JWT)
✅ Database Integration (SQL & NoSQL)
✅ API Performance Optimization (Caching, Load Balancing)
✅ Microservices & Cloud Deployment (Docker, AWS)
I'll help you create a comprehensive Express.js API project that covers all the aspects you mentioned. Let's build a robust API with authentication, database integration, and proper documentation.
First, let's set up a well-organized Express.js API project structure:
server.js
Now, let's create our database configuration:
config/db.js
Let's create our error handling middleware:
middleware/errorHandler.js
Let's implement JWT and OAuth authentication:
middleware/auth.js
Now, let's create our User model:
models/User.js
Let's create a Product model for our API:
models/Product.js
Now, let's implement our authentication routes:
routes/auth.js
Let's implement our user routes:
routes/users.js
Let's implement our product routes:
routes/products.js
Let's create a simple documentation file to explain how to use our API:
docs/API_DOCS.md
Success Response:
Content:
{
"_id": "user_id",
"name": "John Doe",
"email": "john@example.com",
"isAdmin": false,
"apiKey": "generated_api_key",
"token": "jwt_token"
}/auth/loginPOSTBody:
{
"email": "john@example.com",
"password": "password123"
}Success Response:
Content:
{
"_id": "user_id",
"name": "John Doe",
"email": "john@example.com",
"isAdmin": false,
"token": "jwt_token"
}/auth/profileGETHeaders:
Authorization: Bearer jwt_tokenSuccess Response:
Content:
{
"_id": "user_id",
"name": "John Doe",
"email": "john@example.com",
"isAdmin": false
}/auth/api-keyPOSTHeaders:
Authorization: Bearer jwt_tokenSuccess Response:
Content:
{
"apiKey": "new_api_key"
}/productsGETQuery Parameters:
keyword: Search termpage: Page numberSuccess Response:
Content:
{
"products": [
{
"_id": "product_id",
"name": "Product Name",
"price": 99.99,
"description": "Product description",
"image": "image_url",
"brand": "Brand Name",
"category": "Category",
"countInStock": 10,
"rating": 4.5,
"numReviews": 12,
"reviews": []
}
],
"page": 1,
"pages": 5,
"total": 50
}/products/:idGETSuccess Response:
Content:
{
"_id": "product_id",
"name": "Product Name",
"price": 99.99,
"description": "Product description",
"image": "image_url",
"brand": "Brand Name",
"category": "Category",
"countInStock": 10,
"rating": 4.5,
"numReviews": 12,
"reviews": []
}/productsPOSTHeaders:
x-api-key: your_api_keyBody:
{
"name": "Product Name",
"price": 99.99,
"description": "Product description",
"image": "image_url",
"brand": "Brand Name",
"category": "Category",
"countInStock": 10
}Success Response:
/products/:idPUTHeaders:
x-api-key: your_api_keyBody:
{
"name": "Updated Product Name",
"price": 89.99,
"description": "Updated description",
"image": "new_image_url",
"brand": "Updated Brand",
"category": "Updated Category",
"countInStock": 15
}Success Response:
/products/:idDELETEHeaders:
Authorization: Bearer jwt_tokenSuccess Response:
Content:
{
"message": "Product removed"
}/products/:id/reviewsPOSTHeaders:
Authorization: Bearer jwt_tokenBody:
{
"rating": 5,
"comment": "Great product!"
}Success Response:
Content:
{
"message": "Review added"
}/usersGETHeaders:
Authorization: Bearer jwt_tokenSuccess Response:
/users/:idGETHeaders:
Authorization: Bearer jwt_tokenSuccess Response:
/users/:idPUTHeaders:
Authorization: Bearer jwt_tokenBody:
{
"name": "Updated Name",
"email": "updated@example.com",
"isAdmin": true
}Success Response:
/users/:idDELETEHeaders:
Authorization: Bearer jwt_tokenSuccess Response:
Content:
{
"message": "User removed"
}```
Let's create a file with examples of how to test our API using both Postman and CURL:
docs/TESTING.md
{
"email": "test@example.com",
"password": "password123"
}token environment variableHeaders:
Optional Query Params:
Headers:
{
"name": "Test Product",
"price": 99.99,
"description": "This is a test product",
"image": "https://example.com/image.jpg",
"brand": "Test Brand",
"category": "Test Category",
"countInStock": 10
}Headers:
{
"name": "Updated Product",
"price": 89.99,
"description": "This is an updated product"
}Headers:
curl -X POST http://localhost:3000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"name":"CURL User","email":"curl@example.com","password":"password123"}'curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"curl@example.com","password":"password123"}'curl -X GET http://localhost:3000/api/auth/profile \
-H "Authorization: Bearer TOKEN"curl -X GET http://localhost:3000/api/productscurl -X GET "http://localhost:3000/api/products?keyword=product&page=1"curl -X GET http://localhost:3000/api/products/PRODUCT_IDcurl -X POST http://localhost:3000/api/products \
-H "Content-Type: application/json" \
-H "x-api-key: API_KEY" \
-d '{"name":"CURL Product","price":79.99,"description":"Created with CURL","image":"https://example.com/image.jpg","brand":"CURL Brand","category":"CURL Category","countInStock":5}'curl -X PUT http://localhost:3000/api/products/PRODUCT_ID \
-H "Content-Type: application/json" \
-H "x-api-key: API_KEY" \
-d '{"name":"Updated CURL Product","price":69.99}'curl -X DELETE http://localhost:3000/api/products/PRODUCT_ID \
-H "Authorization: Bearer TOKEN"curl -X POST http://localhost:3000/api/products/PRODUCT_ID/reviews \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TOKEN" \
-d '{"rating":5,"comment":"Great product!"}'
## Multi-language Support
Let's create examples of how to interact with our API using different programming languages:
```js project="Express API" file="docs/LANGUAGE_EXAMPLES.md" type="code"
# API Integration Examples
This document provides examples of how to interact with the Express API using different programming languages.
## Node.js Example
```javascript
// Node.js example using fetch API
import fetch from 'node-fetch';
// Configuration
const API_URL = 'http://localhost:3000/api';
let token = '';
let apiKey = '';
// Register a new user
async function registerUser() {
try {
const response = await fetch(`${API_URL}/auth/register`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Node User',
email: 'node@example.com',
password: 'password123',
}),
});
const data = await response.json();
console.log('Registration successful:', data);
token = data.token;
apiKey = data.apiKey;
return data;
} catch (error) {
console.error('Registration failed:', error);
}
}
// Login
async function login() {
try {
const response = await fetch(`${API_URL}/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'node@example.com',
password: 'password123',
}),
});
const data = await response.json();
console.log('Login successful:', data);
token = data.token;
return data;
} catch (error) {
console.error('Login failed:', error);
}
}
// Get user profile
async function getUserProfile() {
try {
const response = await fetch(`${API_URL}/auth/profile`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
},
});
const data = await response.json();
console.log('User profile:', data);
return data;
} catch (error) {
console.error('Failed to get user profile:', error);
}
}
// Create a product
async function createProduct() {
try {
const response = await fetch(`${API_URL}/products`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': apiKey,
},
body: JSON.stringify({
name: 'Node.js Product',
price: 89.99,
description: 'Created with Node.js',
image: 'https://example.com/image.jpg',
brand: 'Node Brand',
category: 'Node Category',
countInStock: 15,
}),
});
const data = await response.json();
console.log('Product created:', data);
return data;
} catch (error) {
console.error('Failed to create product:', error);
}
}
// Get all products
async function getProducts() {
try {
const response = await fetch(`${API_URL}/products`);
const data = await response.json();
console.log('Products:', data);
return data;
} catch (error) {
console.error('Failed to get products:', error);
}
}
// Main function to run the examples
async function main() {
await registerUser();
// If registration fails, try login
if (!token) {
await login();
}
if (token) {
await getUserProfile();
await createProduct();
await getProducts();
}
}
main();import requests
import json
# Configuration
API_URL = 'http://localhost:3000/api'
token = ''
api_key = ''
# Register a new user
def register_user():
global token, api_key
try:
response = requests.post(
f'{API_URL}/auth/register',
headers={'Content-Type': 'application/json'},
json={
'name': 'Python User',
'email': 'python@example.com',
'password': 'password123'
}
)
data = response.json()
print('Registration successful:', data)
token = data.get('token', '')
api_key = data.get('apiKey', '')
return data
except Exception as e:
print('Registration failed:', e)
return None
# Login
def login():
global token
try:
response = requests.post(
f'{API_URL}/auth/login',
headers={'Content-Type': 'application/json'},
json={
'email': 'python@example.com',
'password': 'password123'
}
)
data = response.json()
print('Login successful:', data)
token = data.get('token', '')
return data
except Exception as e:
print('Login failed:', e)
return None
# Get user profile
def get_user_profile():
try:
response = requests.get(
f'{API_URL}/auth/profile',
headers={'Authorization': f'Bearer {token}'}
)
data = response.json()
print('User profile:', data)
return data
except Exception as e:
print('Failed to get user profile:', e)
return None
# Create a product
def create_product():
try:
response = requests.post(
f'{API_URL}/products',
headers={
'Content-Type': 'application/json',
'x-api-key': api_key
},
json={
'name': 'Python Product',
'price': 79.99,
'description': 'Created with Python',
'image': 'https://example.com/image.jpg',
'brand': 'Python Brand',
'category': 'Python Category',
'countInStock': 10
}
)
data = response.json()
print('Product created:', data)
return data
except Exception as e:
print('Failed to create product:', e)
return None
# Get all products
def get_products():
try:
response = requests.get(f'{API_URL}/products')
data = response.json()
print('Products:', data)
return data
except Exception as e:
print('Failed to get products:', e)
return None
# Main function to run the examples
def main():
global token
register_user()
# If registration fails, try login
if not token:
login()
if token:
get_user_profile()
create_product()
get_products()
if __name__ == '__main__':
main()import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class ApiClient {
private static final String API_URL = "http://localhost:3000/api";
private static String token = "";
private static String apiKey = "";
private static final HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(10))
.build();
public static void main(String[] args) {
try {
// Try to register, if it fails, try to login
if (!registerUser()) {
login();
}
if (!token.isEmpty()) {
getUserProfile();
createProduct();
getProducts();
}
} catch (Exception e) {
e.printStackTrace();
}
}
// Register a new user
private static boolean registerUser() {
try {
String requestBody = "{\"name\":\"Java User\",\"email\":\"java@example.com\",\"password\":\"password123\"}";
HttpRequest request = HttpRequest.newBuilder()
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.uri(URI.create(API_URL + "/auth/register"))
.header("Content-Type", "application/json")
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Registration Response: " + response.body());
// Simple parsing - in a real app, use a JSON library
if (response.body().contains("token")) {
token = extractValue(response.body(), "token");
apiKey = extractValue(response.body(), "apiKey");
return true;
}
return false;
} catch (Exception e) {
System.out.println("Registration failed: " + e.getMessage());
return false;
}
}
// Login
private static boolean login() {
try {
String requestBody = "{\"email\":\"java@example.com\",\"password\":\"password123\"}";
HttpRequest request = HttpRequest.newBuilder()
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.uri(URI.create(API_URL + "/auth/login"))
.header("Content-Type", "application/json")
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Login Response: " + response.body());
if (response.body().contains("token")) {
token = extractValue(response.body(), "token");
return true;
}
return false;
} catch (Exception e) {
System.out.println("Login failed: " + e.getMessage());
return false;
}
}
// Get user profile
private static void getUserProfile() throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.GET()
.uri(URI.create(API_URL + "/auth/profile"))
.header("Authorization", "Bearer " + token)
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("User Profile: " + response.body());
}
// Create a product
private static void createProduct() throws IOException, InterruptedException {
String requestBody = "{\"name\":\"Java Product\",\"price\":69.99,\"description\":\"Created with Java\",\"image\":\"https://example.com/image.jpg\",\"brand\":\"Java Brand\",\"category\":\"Java Category\",\"countInStock\":5}";
HttpRequest request = HttpRequest.newBuilder()
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.uri(URI.create(API_URL + "/products"))
.header("Content-Type", "application/json")
.header("x-api-key", apiKey)
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Create Product Response: " + response.body());
}
// Get all products
private static void getProducts() throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.GET()
.uri(URI.create(API_URL + "/products"))
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Products: " + response.body());
}
// Simple method to extract values from JSON response
// In a real application, use a proper JSON library like Jackson or Gson
private static String extractValue(String json, String key) {
String searchKey = "\"" + key + "\":\"";
int start = json.indexOf(searchKey) + searchKey.length();
int end = json.indexOf("\"", start);
if (start != -1 && end != -1) {
return json.substring(start, end);
}
return "";
}
}
## REST vs GraphQL Comparison
Let's create a document comparing REST and GraphQL approaches:
```js project="Express API" file="docs/REST_VS_GRAPHQL.md" type="code"
# REST vs GraphQL
This document provides a comparison between REST and GraphQL API architectures, highlighting their differences, advantages, and use cases.
## REST (Representational State Transfer)
REST is an architectural style that uses HTTP methods to interact with resources.
### Key Characteristics of REST
1. **Resource-Based**: Resources are identified by URLs
2. **HTTP Methods**: Uses standard HTTP methods (GET, POST, PUT, DELETE)
3. **Stateless**: Each request contains all information needed to complete it
4. **Uniform Interface**: Consistent way to interact with resources
5. **Client-Server Architecture**: Clear separation of concerns
### REST Endpoints in Our API
Our Express API follows RESTful principles:
- `GET /api/products`: Get all products
- `GET /api/products/:id`: Get a specific product
- `POST /api/products`: Create a new product
- `PUT /api/products/:id`: Update a product
- `DELETE /api/products/:id`: Delete a product
### Advantages of REST
1. **Simplicity**: Easy to understand and implement
2. **Scalability**: Stateless nature makes it highly scalable
3. **Caching**: HTTP caching mechanisms can be leveraged
4. **Tooling**: Wide range of tools and libraries available
5. **Browser Support**: Works well with browser URLs and history
### Disadvantages of REST
1. **Over-fetching**: May return more data than needed
2. **Under-fetching**: May require multiple requests to get all needed data
3. **Versioning**: API versioning can be challenging
4. **Documentation**: Requires external documentation tools
## GraphQL
GraphQL is a query language for APIs and a runtime for executing those queries.
### Key Characteristics of GraphQL
1. **Query Language**: Clients specify exactly what data they need
2. **Single Endpoint**: Typically uses a single endpoint for all operations
3. **Strong Typing**: Schema defines available data and operations
4. **Hierarchical**: Queries mirror the shape of the response
5. **Introspection**: API can be queried for its own schema
### Example GraphQL Schema (if we were to implement it)
```graphql
type User {
id: ID!
name: String!
email: String!
isAdmin: Boolean!
products: [Product!]
}
type Product {
id: ID!
name: String!
price: Float!
description: String!
image: String!
brand: String!
category: String!
countInStock: Int!
rating: Float!
numReviews: Int!
reviews: [Review!]
user: User!
}
type Review {
id: ID!
rating: Int!
comment: String!
user: User!
}
type Query {
products(keyword: String, page: Int): ProductsResult!
product(id: ID!): Product
users: [User!]!
user(id: ID!): User
me: User
}
type ProductsResult {
products: [Product!]!
page: Int!
pages: Int!
total: Int!
}
type Mutation {
createProduct(input: ProductInput!): Product!
updateProduct(id: ID!, input: ProductInput!): Product!
deleteProduct(id: ID!): Boolean!
createReview(productId: ID!, rating: Int!, comment: String!): Review!
register(name: String!, email: String!, password: String!): AuthPayload!
login(email: String!, password: String!): AuthPayload!
}
input ProductInput {
name: String!
price: Float!
description: String!
image: String!
brand: String!
category: String!
countInStock: Int!
}
type AuthPayload {
token: String!
user: User!
}Many modern applications use both REST and GraphQL:
Both REST and GraphQL have their strengths and weaknesses. The choice between them depends on your specific application requirements, team expertise, and client needs. Our Express API currently uses REST, but could be extended with GraphQL capabilities if needed in the future.
## Environment Setup
Let's create a sample `.env` file for our project:
```js project="Express API" file=".env.example" type="code"
# Server Configuration
PORT=3000
NODE_ENV=development
# MongoDB Connection
MONGO_URI=mongodb://localhost:27017/express-api
# JWT Configuration
JWT_SECRET=your_jwt_secret_key_here
JWT_EXPIRE=30d
# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000 # 15 minutes
RATE_LIMIT_MAX=100
# CORS Configuration
CORS_ORIGIN=*
# OAuth Configuration (if implementing)
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
# API Documentation
API_URL=http://localhost:3000/apiLet's create a guide for deploying our Express API to Vercel:
docs/DEPLOYMENT.md
Ensure your server code exports the Express app. In server.js, make sure you have:
// ... existing code ...
// Start server if not being imported
if (require.main === module) {
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
}
// Export the Express app
export default app;npm install -g vercelvercel loginNavigate to your project directory and run:
vercelFollow the prompts to configure your deployment. When asked if you want to override the settings, choose "No" to use the settings from your vercel.json file.
After deployment, you need to set up your environment variables in the Vercel dashboard:
.env fileFor production, you should use a hosted MongoDB service like MongoDB Atlas:
MONGO_URI environment variable in VercelWhen you're ready to deploy to production, run:
vercel --prodVercel serverless functions have some limitations:
Serverless functions experience "cold starts" when they haven't been used for a while. To minimize the impact:
Use Vercel's built-in analytics and logging to monitor your API:
If Vercel's serverless model doesn't fit your needs, consider these alternatives:
For more information on deploying Express.js applications to Vercel, see the official Vercel documentation 1.
## Conclusion
This Express.js API project provides a comprehensive foundation for building robust APIs with authentication, database integration, and proper documentation. You can extend it further by adding features like:
1. GraphQL support alongside REST
2. WebSocket integration for real-time features
3. More sophisticated caching strategies
4. Microservices architecture
5. Containerization with Docker
The project structure follows best practices and includes security measures like rate limiting, helmet protection, and proper authentication.
<Actions>
<Action name="Add database integration" description="Integrate with MongoDB or another database" />
<Action name="Implement OAuth authentication" description="Add Google, GitHub, or Facebook OAuth" />
<Action name="Add GraphQL support" description="Implement GraphQL alongside REST endpoints" />
<Action name="Create API documentation" description="Generate Swagger/OpenAPI documentation" />
<Action name="Set up Docker containerization" description="Containerize the API for easier deployment" />
</Actions>
Please make sure to add the following environment variables to your project:
<AddEnvironmentVariables names={["PORT", "MONGO_URI", "JWT_SECRET"]} />