🚀 Setting Up API Development: Simple Guide
Let’s set up API development on your Alpine Linux system! 🌐 This guide uses easy steps and simple words. We’ll create web services that communicate with applications! 😊
🤔 What is API Development?
API development is like building bridges that let different software programs talk to each other!
Think of APIs like:
- 📝 A translator that helps applications communicate
- 🔧 A waiter that takes orders and brings back responses
- 💡 A set of rules for how programs share information
🎯 What You Need
Before we start, you need:
- ✅ Alpine Linux system running
- ✅ Basic programming knowledge (Python, Node.js, or Go)
- ✅ Understanding of HTTP and web concepts
- ✅ Root access or sudo permissions
📋 Step 1: Install Development Tools
Set Up Programming Environment
First, let’s install the tools we need for API development! 😊
What we’re doing: Installing multiple programming languages and frameworks commonly used for API development.
# Update package lists
apk update
# Install Node.js and npm for JavaScript APIs
apk add nodejs npm
# Install Python and pip for Python APIs
apk add python3 py3-pip
# Install Go for high-performance APIs
apk add go
# Install development tools
apk add git curl wget
# Install database tools
apk add sqlite postgresql-client
# Install text editors
apk add vim nano
# Verify installations
node --version
python3 --version
go version
What this does: 📖 Gives you multiple options for creating APIs with different programming languages.
Example output:
(1/12) Installing nodejs (20.5.1-r0)
(2/12) Installing npm (9.8.0-r0)
(3/12) Installing python3 (3.11.6-r0)
...
OK: 185 packages installed
v20.5.1
Python 3.11.6
go version go1.21.3 linux/amd64
What this means: API development environment is ready! ✅
💡 Important Tips
Tip: Choose the language that best fits your project needs! 💡
Warning: Always validate and sanitize API inputs for security! ⚠️
🛠️ Step 2: Create Your First API
Build a Simple REST API with Node.js
Now let’s create a basic REST API! 😊
What we’re doing: Creating a simple web API that can handle HTTP requests and return JSON responses.
# Create project directory
mkdir -p ~/api-projects/simple-api
cd ~/api-projects/simple-api
# Initialize Node.js project
npm init -y
# Install Express.js framework
npm install express
# Install additional useful packages
npm install cors helmet morgan dotenv
# Create main API file
cat > server.js << 'EOF'
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
// Create Express app
const app = express();
const port = process.env.PORT || 3000;
// Middleware
app.use(helmet()); // Security headers
app.use(cors()); // Enable CORS
app.use(morgan('combined')); // Logging
app.use(express.json()); // Parse JSON bodies
// Sample data
let users = [
{ id: 1, name: 'Alice', email: '[email protected]' },
{ id: 2, name: 'Bob', email: '[email protected]' },
{ id: 3, name: 'Charlie', email: '[email protected]' }
];
// Routes
app.get('/', (req, res) => {
res.json({
message: 'Welcome to Simple API!',
version: '1.0.0',
endpoints: ['/users', '/users/:id', '/health']
});
});
// Get all users
app.get('/users', (req, res) => {
res.json({
success: true,
data: users,
count: users.length
});
});
// Get user by ID
app.get('/users/:id', (req, res) => {
const id = parseInt(req.params.id);
const user = users.find(u => u.id === id);
if (!user) {
return res.status(404).json({
success: false,
message: 'User not found'
});
}
res.json({
success: true,
data: user
});
});
// Create new user
app.post('/users', (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({
success: false,
message: 'Name and email are required'
});
}
const newUser = {
id: users.length + 1,
name,
email
};
users.push(newUser);
res.status(201).json({
success: true,
data: newUser,
message: 'User created successfully'
});
});
// Update user
app.put('/users/:id', (req, res) => {
const id = parseInt(req.params.id);
const userIndex = users.findIndex(u => u.id === id);
if (userIndex === -1) {
return res.status(404).json({
success: false,
message: 'User not found'
});
}
const { name, email } = req.body;
users[userIndex] = { id, name, email };
res.json({
success: true,
data: users[userIndex],
message: 'User updated successfully'
});
});
// Delete user
app.delete('/users/:id', (req, res) => {
const id = parseInt(req.params.id);
const userIndex = users.findIndex(u => u.id === id);
if (userIndex === -1) {
return res.status(404).json({
success: false,
message: 'User not found'
});
}
users.splice(userIndex, 1);
res.json({
success: true,
message: 'User deleted successfully'
});
});
// Health check endpoint
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime()
});
});
// Start server
app.listen(port, () => {
console.log(`🚀 API server running on http://localhost:${port}`);
console.log(`📚 API documentation available at http://localhost:${port}`);
});
EOF
# Create package.json scripts
npm pkg set scripts.start="node server.js"
npm pkg set scripts.dev="node server.js"
Great job! Your first API is created! 🌟
🎮 Step 3: Test Your API
Verify API Functionality
Let’s test our API to make sure it works! 🎯
What we’re doing: Starting the API server and testing all the endpoints to ensure they work correctly.
# Start the API server
npm start &
# Wait a moment for server to start
sleep 2
# Test the root endpoint
curl http://localhost:3000/
# Test getting all users
curl http://localhost:3000/users
# Test getting a specific user
curl http://localhost:3000/users/1
# Test creating a new user
curl -X POST http://localhost:3000/users \
-H "Content-Type: application/json" \
-d '{"name": "Diana", "email": "[email protected]"}'
# Test updating a user
curl -X PUT http://localhost:3000/users/2 \
-H "Content-Type: application/json" \
-d '{"name": "Robert", "email": "[email protected]"}'
# Test health check
curl http://localhost:3000/health
# Check server logs
jobs
You should see:
🚀 API server running on http://localhost:3000
📚 API documentation available at http://localhost:3000
{"message":"Welcome to Simple API!","version":"1.0.0","endpoints":["/users","/users/:id","/health"]}
{"success":true,"data":[{"id":1,"name":"Alice","email":"[email protected]"},{"id":2,"name":"Bob","email":"[email protected]"},{"id":3,"name":"Charlie","email":"[email protected]"}],"count":3}
{"success":true,"data":{"id":1,"name":"Alice","email":"[email protected]"}}
{"success":true,"data":{"id":4,"name":"Diana","email":"[email protected]"},"message":"User created successfully"}
Awesome work! Your API is working perfectly! 🌟
📊 Step 4: Add Database Integration
Connect to SQLite Database
Now let’s add a real database to our API! 😊
What we’re doing: Replacing the in-memory array with a SQLite database for persistent data storage.
# Install SQLite package for Node.js
npm install sqlite3
# Create database initialization script
cat > init-db.js << 'EOF'
const sqlite3 = require('sqlite3').verbose();
// Create database
const db = new sqlite3.Database('./api.db');
// Create users table
db.serialize(() => {
db.run(`CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`);
// Insert sample data
const stmt = db.prepare("INSERT OR IGNORE INTO users (name, email) VALUES (?, ?)");
stmt.run("Alice", "[email protected]");
stmt.run("Bob", "[email protected]");
stmt.run("Charlie", "[email protected]");
stmt.finalize();
console.log("✅ Database initialized successfully!");
});
db.close();
EOF
# Run database initialization
node init-db.js
# Create updated server with database
cat > server-db.js << 'EOF'
const express = require('express');
const sqlite3 = require('sqlite3').verbose();
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
const app = express();
const port = process.env.PORT || 3000;
// Database connection
const db = new sqlite3.Database('./api.db');
// Middleware
app.use(helmet());
app.use(cors());
app.use(morgan('combined'));
app.use(express.json());
// Helper function to run database queries
const runQuery = (query, params = []) => {
return new Promise((resolve, reject) => {
db.all(query, params, (err, rows) => {
if (err) reject(err);
else resolve(rows);
});
});
};
// Get all users
app.get('/users', async (req, res) => {
try {
const users = await runQuery('SELECT * FROM users ORDER BY id');
res.json({
success: true,
data: users,
count: users.length
});
} catch (error) {
res.status(500).json({
success: false,
message: 'Database error',
error: error.message
});
}
});
// Get user by ID
app.get('/users/:id', async (req, res) => {
try {
const users = await runQuery('SELECT * FROM users WHERE id = ?', [req.params.id]);
if (users.length === 0) {
return res.status(404).json({
success: false,
message: 'User not found'
});
}
res.json({
success: true,
data: users[0]
});
} catch (error) {
res.status(500).json({
success: false,
message: 'Database error',
error: error.message
});
}
});
// Create new user
app.post('/users', (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({
success: false,
message: 'Name and email are required'
});
}
db.run('INSERT INTO users (name, email) VALUES (?, ?)', [name, email], function(err) {
if (err) {
if (err.code === 'SQLITE_CONSTRAINT') {
return res.status(400).json({
success: false,
message: 'Email already exists'
});
}
return res.status(500).json({
success: false,
message: 'Database error',
error: err.message
});
}
res.status(201).json({
success: true,
data: { id: this.lastID, name, email },
message: 'User created successfully'
});
});
});
app.listen(port, () => {
console.log(`🚀 API with database running on http://localhost:${port}`);
});
EOF
# Stop previous server and start new one
pkill node
npm pkg set scripts.start="node server-db.js"
npm start &
What this creates:
api.db # SQLite database file
users table:
- id (INTEGER PRIMARY KEY)
- name (TEXT)
- email (TEXT UNIQUE)
- created_at (DATETIME)
Awesome work! Your API now has persistent database storage! 🌟
🎮 Let’s Try It!
Time for hands-on practice! This is the fun part! 🎯
What we’re doing: Testing the database-powered API with more advanced features.
# Test database API
curl http://localhost:3000/users
# Create a user with database persistence
curl -X POST http://localhost:3000/users \
-H "Content-Type: application/json" \
-d '{"name": "Eve", "email": "[email protected]"}'
# Try to create duplicate email (should fail)
curl -X POST http://localhost:3000/users \
-H "Content-Type: application/json" \
-d '{"name": "Evil Eve", "email": "[email protected]"}'
# Check the database directly
sqlite3 api.db "SELECT * FROM users;"
# Test API performance
for i in {1..5}; do
time curl -s http://localhost:3000/users > /dev/null
done
You should see:
{"success":true,"data":[{"id":1,"name":"Alice","email":"[email protected]","created_at":"2025-06-03 16:30:00"},{"id":2,"name":"Bob","email":"[email protected]","created_at":"2025-06-03 16:30:00"}],"count":2}
{"success":true,"data":{"id":4,"name":"Eve","email":"[email protected]"},"message":"User created successfully"}
{"success":false,"message":"Email already exists"}
1|Alice|[email protected]|2025-06-03 16:30:00
2|Bob|[email protected]|2025-06-03 16:30:00
4|Eve|[email protected]|2025-06-03 16:32:15
Awesome work! Database-powered API is working perfectly! 🌟
📊 Quick Summary Table
What to Do | Command | Result |
---|---|---|
🔧 Install Node.js | apk add nodejs npm | ✅ Runtime ready |
🛠️ Create API | express server.js | ✅ REST endpoints |
🎯 Add database | sqlite3 integration | ✅ Persistent storage |
🚀 Test API | curl localhost:3000 | ✅ Working API |
🌐 Step 5: Add Advanced Features
Implement Authentication and Documentation
Let’s add professional API features! 🌐
What we’re doing: Adding JWT authentication and API documentation to make our API production-ready.
# Install additional packages
npm install jsonwebtoken bcryptjs swagger-ui-express swagger-jsdoc
# Create authentication middleware
cat > auth.js << 'EOF'
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key';
// Generate JWT token
const generateToken = (userId) => {
return jwt.sign({ userId }, JWT_SECRET, { expiresIn: '24h' });
};
// Verify JWT token middleware
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({
success: false,
message: 'Access token required'
});
}
jwt.verify(token, JWT_SECRET, (err, user) => {
if (err) {
return res.status(403).json({
success: false,
message: 'Invalid or expired token'
});
}
req.user = user;
next();
});
};
// Hash password
const hashPassword = async (password) => {
return await bcrypt.hash(password, 10);
};
// Compare password
const comparePassword = async (password, hash) => {
return await bcrypt.compare(password, hash);
};
module.exports = {
generateToken,
authenticateToken,
hashPassword,
comparePassword
};
EOF
# Create API documentation
cat > swagger.js << 'EOF'
const swaggerJSDoc = require('swagger-jsdoc');
const options = {
definition: {
openapi: '3.0.0',
info: {
title: 'Simple API',
version: '1.0.0',
description: 'A simple Express API with authentication',
},
servers: [
{
url: 'http://localhost:3000',
description: 'Development server',
},
],
components: {
securitySchemes: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
},
},
},
},
apis: ['./server-auth.js'], // Path to the API files
};
const specs = swaggerJSDoc(options);
module.exports = specs;
EOF
# Create enhanced server with auth and docs
cat > server-auth.js << 'EOF'
const express = require('express');
const swaggerUi = require('swagger-ui-express');
const swaggerSpecs = require('./swagger');
const { authenticateToken, generateToken } = require('./auth');
const app = express();
const port = process.env.PORT || 3000;
app.use(express.json());
/**
* @swagger
* /api-docs:
* get:
* summary: API Documentation
* description: Swagger UI for API documentation
*/
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
/**
* @swagger
* /auth/login:
* post:
* summary: Login user
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* email:
* type: string
* password:
* type: string
*/
app.post('/auth/login', (req, res) => {
const { email, password } = req.body;
// Simple auth for demo (use real auth in production)
if (email === '[email protected]' && password === 'password') {
const token = generateToken(1);
res.json({
success: true,
token,
message: 'Login successful'
});
} else {
res.status(401).json({
success: false,
message: 'Invalid credentials'
});
}
});
/**
* @swagger
* /protected:
* get:
* summary: Protected endpoint
* security:
* - bearerAuth: []
*/
app.get('/protected', authenticateToken, (req, res) => {
res.json({
success: true,
message: 'Access granted to protected route',
user: req.user
});
});
app.listen(port, () => {
console.log(`🚀 API with auth running on http://localhost:${port}`);
console.log(`📚 API docs available at http://localhost:${port}/api-docs`);
});
EOF
# Update package scripts
npm pkg set scripts.start="node server-auth.js"
What this does: Adds professional-grade authentication and self-documenting API features! 📚
Example: API Testing and Monitoring 🟡
What we’re doing: Setting up comprehensive testing and monitoring for our API.
# Install testing packages
npm install --save-dev jest supertest
# Create API tests
cat > api.test.js << 'EOF'
const request = require('supertest');
const app = require('./server-auth');
describe('API Tests', () => {
test('GET /health should return healthy status', async () => {
const response = await request(app)
.get('/health')
.expect(200);
expect(response.body.status).toBe('healthy');
});
test('POST /auth/login with valid credentials', async () => {
const response = await request(app)
.post('/auth/login')
.send({
email: '[email protected]',
password: 'password'
})
.expect(200);
expect(response.body.success).toBe(true);
expect(response.body.token).toBeDefined();
});
test('GET /protected without token should fail', async () => {
await request(app)
.get('/protected')
.expect(401);
});
});
EOF
# Add test script
npm pkg set scripts.test="jest"
# Run tests
npm test
# Create simple monitoring script
cat > monitor.js << 'EOF'
const axios = require('axios');
const checkHealth = async () => {
try {
const response = await axios.get('http://localhost:3000/health');
console.log(`✅ API Health: ${response.data.status} (${response.status})`);
} catch (error) {
console.log(`❌ API Down: ${error.message}`);
}
};
// Check every 30 seconds
setInterval(checkHealth, 30000);
checkHealth(); // Check immediately
EOF
What this does: Provides automated testing and health monitoring for your API! 🌟
🚨 Fix Common Problems
Problem 1: Port already in use ❌
What happened: Another process is using port 3000. How to fix it: Find and kill the process or use a different port!
# Find process using port 3000
lsof -i :3000
netstat -tulpn | grep 3000
# Kill process using port
pkill -f node
# Or use different port
PORT=3001 npm start
Problem 2: Database connection errors ❌
What happened: SQLite database access issues. How to fix it: Check permissions and file paths!
# Check database file permissions
ls -la api.db
# Fix permissions if needed
chmod 664 api.db
# Test database directly
sqlite3 api.db ".tables"
sqlite3 api.db "SELECT COUNT(*) FROM users;"
Problem 3: Authentication not working ❌
What happened: JWT tokens are invalid or expired. How to fix it: Check token format and secret!
# Test authentication flow
curl -X POST http://localhost:3000/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "password": "password"}'
# Use token in protected route
TOKEN="your-jwt-token-here"
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:3000/protected
Don’t worry! These problems happen to everyone. You’re doing great! 💪
💡 Simple Tips
- Use environment variables 📅 - Keep secrets out of code
- Validate all inputs 🌱 - Prevent security vulnerabilities
- Add proper error handling 🤝 - Make APIs robust
- Document your endpoints 💪 - Help other developers
✅ Check Everything Works
Let’s make sure everything is working:
# Stop any running servers
pkill node
# Start the enhanced API
npm start &
sleep 3
# Test basic functionality
curl http://localhost:3000/health
# Test authentication
curl -X POST http://localhost:3000/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "password": "password"}'
# Check API documentation
curl http://localhost:3000/api-docs
# Run automated tests
npm test
# Check server logs
jobs
# You should see this
echo "API development environment is working perfectly! ✅"
Good output:
🚀 API with auth running on http://localhost:3000
📚 API docs available at http://localhost:3000/api-docs
{"status":"healthy","timestamp":"2025-06-03T16:45:12.345Z","uptime":123.456}
{"success":true,"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","message":"Login successful"}
PASS ./api.test.js
✓ GET /health should return healthy status (25ms)
✓ POST /auth/login with valid credentials (15ms)
✓ GET /protected without token should fail (10ms)
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
✅ Success! API development environment is production-ready.
🏆 What You Learned
Great job! Now you can:
- ✅ Set up API development environments on Alpine Linux
- ✅ Create REST APIs with Node.js and Express
- ✅ Integrate databases for persistent data storage
- ✅ Implement authentication and authorization
- ✅ Add API documentation and automated testing
🎯 What’s Next?
Now you can try:
- 📚 Building GraphQL APIs for flexible data querying
- 🛠️ Implementing rate limiting and API versioning
- 🤝 Creating microservices architecture
- 🌟 Deploying APIs with Docker and Kubernetes!
Remember: Every expert was once a beginner. You’re doing amazing! 🎉
Keep practicing and you’ll become an API development expert too! 💫