Building Your First Server
Imagine you're opening a restaurant. Just as a restaurant needs a building where customers can come in and place their orders, a web application needs a server where clients can send their requests. Let's create our first server using Node.js's built-in http package.
const http = require('http');
const server = http.createServer((request, response) => {
console.log('A customer has arrived!');
response.end('Welcome to our restaurant!');
});
server.listen(3000, () => {
console.log('Server is ready to take orders on port 3000');
});
Think of this server as a restaurant host who's always ready to greet customers and handle their requests. The createServer function is like hiring this host, and the listen method is like opening the restaurant's doors for business.
Understanding Request and Response Objects
In our restaurant analogy, the Request object is like a customer's order ticket, containing all the details about what they want. The Response object is like the plate of food we send back to their table.
The Request Object: Your Customer's Order
The request object contains crucial information about what the client wants:
const server = http.createServer((request, response) => {
console.log('Method (type of order):', request.method);
console.log('URL (specific dish):', request.url);
console.log('Headers (special instructions):', request.headers);
});
The Response Object: Your Service Back to the Client
The response object is how we send back what was requested:
const server = http.createServer((request, response) => {
// Set the status code (like confirming order status)
response.statusCode = 200; // "Your order was successful!"
// Set headers (like placing utensils and napkins)
response.setHeader('Content-Type', 'application/json');
// Send the response (serving the food)
response.end(JSON.stringify({ message: 'Your order is ready!' }));
});
Reading Request Components
Just as a waiter needs to understand different types of orders, your server needs to handle different types of requests.
const server = http.createServer((request, response) => {
// Reading the method (GET, POST, etc.)
if (request.method === 'GET') {
// Customer is asking for menu items
handleGetRequest(request, response);
} else if (request.method === 'POST') {
// Customer is placing an order
handlePostRequest(request, response);
}
// Reading the URL (what specifically they want)
if (request.url === '/menu') {
// Show the menu
sendMenu(response);
} else if (request.url === '/order') {
// Take their order
takeOrder(request, response);
}
});
function handleGetRequest(request, response) {
// Implementation details for handling GET requests
response.setHeader('Content-Type', 'application/json');
response.end(JSON.stringify({ message: 'Here is our menu!' }));
}
Sending Static Assets
Sometimes you need to serve static files like images, CSS, or JavaScript files. Think of this like having pre-prepared meals ready to serve:
const fs = require('fs');
const path = require('path');
const server = http.createServer((request, response) => {
if (request.url === '/menu-image.jpg') {
// Read the image file
fs.readFile(path.join(__dirname, 'menu-image.jpg'), (error, content) => {
if (error) {
response.statusCode = 500;
response.end('Error loading the image');
return;
}
response.setHeader('Content-Type', 'image/jpeg');
response.end(content);
});
}
});
Debugging Server Issues
When your server isn't responding as expected, it's like having a kitchen that's backed up. Here are common issues and solutions:
Hanging Server
If your server seems frozen, check these common causes:
// Always end your response!
const server = http.createServer((request, response) => {
if (request.url === '/menu') {
response.write('Here is our menu');
response.end(); // Don't forget this!
}
// Missing else block could cause hanging
else {
response.statusCode = 404;
response.end('Not found');
}
});
Using Postman for Testing
Postman is like a food critic who helps you test your restaurant's service. You can use it to:
- Send different types of requests (GET, POST, PUT, DELETE)
- Add custom headers
- Include request bodies
- View response status codes and headers
Real-World Applications
Here's a practical example of a simple API endpoint for a restaurant ordering system:
const http = require('http');
const menu = {
appetizers: ['Salad', 'Soup'],
mainCourse: ['Steak', 'Fish'],
desserts: ['Cake', 'Ice Cream']
};
const server = http.createServer((request, response) => {
response.setHeader('Content-Type', 'application/json');
if (request.url === '/api/menu' && request.method === 'GET') {
response.statusCode = 200;
response.end(JSON.stringify(menu));
}
else if (request.url === '/api/order' && request.method === 'POST') {
let body = '';
request.on('data', chunk => {
body += chunk.toString();
});
request.on('end', () => {
const order = JSON.parse(body);
// Process the order
response.statusCode = 201;
response.end(JSON.stringify({
message: 'Order received!',
orderNumber: Math.floor(Math.random() * 1000)
}));
});
}
else {
response.statusCode = 404;
response.end(JSON.stringify({ error: 'Not found' }));
}
});
server.listen(3000, () => {
console.log('Restaurant server is open for business!');
});
Topics to Explore Further
To deepen your understanding of server-side programming, consider exploring:
- Express.js - A more robust framework for building web applications
- RESTful API design principles
- Authentication and authorization
- Error handling and logging
- Database integration
- Middleware concepts
- WebSocket for real-time communication
- Server-side caching strategies