01How The Internet Works 02Your First Node.js Server 03HTTP Methods and JSON 04Express.js Framework 05Building REST APIs 06MongoDB Fundamentals 07Mongoose ODM 08Data Modeling 09Authentication Basics 10JWT Implementation

Settings

Theme
Sand
Cloud
Midnight
Forest
Sunset
Purple
Ocean
Crimson
Font
Merriweather
Inter
JetBrains
Space Grotesk
Fira Code
Playfair
Font Size
100%
Bookmark
No bookmark set
Day 3

HTTP Methods and JSON

Yesterday you built a server that responds to requests. Today you learn the different types of requests (HTTP methods) and JSON - the universal data format that APIs use to communicate.

HTTP Methods - The Verbs of the Web

HTTP methods tell the server what you want to do. Think of them as verbs - actions you want to perform on a resource.

The Main HTTP Methods

  • GET - Retrieve data (Read)
  • POST - Create new data (Create)
  • PUT - Update existing data completely (Replace)
  • PATCH - Update existing data partially (Modify)
  • DELETE - Remove data (Delete)
Real World Analogy

Think of a library. GET is reading a book. POST is donating a new book. PUT is replacing a book with a new edition. PATCH is fixing a typo in a book. DELETE is removing a book from the collection.

GET Requests

GET retrieves data without modifying anything. It is the most common request - every time you visit a URL, your browser makes a GET request.

GET Request Examples
# Get all users
GET /api/users

# Get a specific user by ID
GET /api/users/123

# Get users with query parameters (filtering)
GET /api/users?role=admin&active=true

# Get users with pagination
GET /api/users?page=2&limit=10
Key Point

GET requests should NEVER modify data. They should be idempotent - calling them multiple times produces the same result. GET requests also should not have a request body.

POST Requests

POST creates new resources. It sends data in the request body and typically returns the created resource.

POST Request Example
# Create a new user
POST /api/users
Content-Type: application/json

{
    "name": "John Doe",
    "email": "john@example.com",
    "password": "secret123"
}

# Response: 201 Created
{
    "id": 456,
    "name": "John Doe",
    "email": "john@example.com",
    "createdAt": "2024-01-15T10:30:00Z"
}

PUT Requests

PUT replaces an entire resource. You send the complete new version.

PUT Request Example
# Replace user 456 completely
PUT /api/users/456
Content-Type: application/json

{
    "name": "John Smith",
    "email": "johnsmith@example.com",
    "role": "admin"
}

# Response: 200 OK with updated resource

PATCH Requests

PATCH updates only specific fields, leaving others unchanged.

PATCH Request Example
# Update ONLY the email of user 456
PATCH /api/users/456
Content-Type: application/json

{
    "email": "newemail@example.com"
}

# Other fields (name, role) remain unchanged

DELETE Requests

DELETE removes a resource. It usually returns 204 No Content on success.

DELETE Request Example
# Delete user 456
DELETE /api/users/456

# Response: 204 No Content (success, no body)
# Or: 200 OK with { "message": "User deleted" }

What is JSON?

JSON (JavaScript Object Notation) is a text format for storing and transmitting data. It is the standard format for APIs because it is:

JSON Syntax
{
    "string": "Hello World",          // Text in double quotes
    "number": 42,                      // Integer or decimal
    "decimal": 3.14159,                // Floating point
    "boolean": true,                   // true or false (lowercase!)
    "nullValue": null,                 // null (lowercase!)
    "array": [1, 2, 3, "mixed", true], // Ordered list
    "object": {                        // Nested object
        "nested": "value",
        "deep": {
            "level": 3
        }
    }
}
JSON Rules

Keys must be strings in double quotes. No trailing commas. No comments (unlike JavaScript). Strings must use double quotes, not single. Boolean and null are lowercase.

JSON in Node.js

Working with JSON
// JavaScript object
const user = {
    name: 'John',
    age: 30,
    hobbies: ['coding', 'gaming']
};

// Convert JavaScript object to JSON string
const jsonString = JSON.stringify(user);
console.log(jsonString);
// Output: {"name":"John","age":30,"hobbies":["coding","gaming"]}

// Pretty print with indentation
const prettyJson = JSON.stringify(user, null, 2);
console.log(prettyJson);
// Output:
// {
//   "name": "John",
//   "age": 30,
//   "hobbies": ["coding", "gaming"]
// }

// Convert JSON string back to JavaScript object
const parsed = JSON.parse(jsonString);
console.log(parsed.name);  // John
console.log(parsed.hobbies[0]);  // coding

Handling POST Requests with JSON

In raw Node.js, request bodies come in chunks that you need to collect. Here is how:

server.js - Handling POST with JSON Body
const http = require('http');

// Simple in-memory database
let users = [
    { id: 1, name: 'Alice', email: 'alice@example.com' },
    { id: 2, name: 'Bob', email: 'bob@example.com' }
];
let nextId = 3;

const server = http.createServer((req, res) => {
    const { method, url } = req;

    // Set JSON response headers
    res.setHeader('Content-Type', 'application/json');

    // GET /api/users - Return all users
    if (method === 'GET' && url === '/api/users') {
        res.statusCode = 200;
        res.end(JSON.stringify(users));
        return;
    }

    // POST /api/users - Create a new user
    if (method === 'POST' && url === '/api/users') {
        let body = '';

        // Collect data chunks as they arrive
        req.on('data', (chunk) => {
            body += chunk.toString();
        });

        // All data received
        req.on('end', () => {
            try {
                // Parse JSON body
                const data = JSON.parse(body);

                // Validate required fields
                if (!data.name || !data.email) {
                    res.statusCode = 400;
                    res.end(JSON.stringify({
                        error: 'Name and email are required'
                    }));
                    return;
                }

                // Create new user
                const newUser = {
                    id: nextId++,
                    name: data.name,
                    email: data.email
                };

                // Add to our "database"
                users.push(newUser);

                // Return created user with 201 status
                res.statusCode = 201;
                res.end(JSON.stringify(newUser));
            } catch (error) {
                // Invalid JSON
                res.statusCode = 400;
                res.end(JSON.stringify({
                    error: 'Invalid JSON'
                }));
            }
        });
        return;
    }

    // 404 for unmatched routes
    res.statusCode = 404;
    res.end(JSON.stringify({ error: 'Not Found' }));
});

server.listen(3000, () => {
    console.log('Server running on http://localhost:3000');
});

Testing Your API

Use these tools to test your API endpoints:

Testing with cURL (Terminal)
# GET all users
curl http://localhost:3000/api/users

# POST - Create new user
curl -X POST http://localhost:3000/api/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Charlie", "email": "charlie@test.com"}'

# Pretty print JSON output
curl http://localhost:3000/api/users | json_pp

API Testing Tools

  • Postman - Popular GUI tool for API testing
  • Insomnia - Clean, fast alternative to Postman
  • Thunder Client - VS Code extension
  • cURL - Command line tool (built into Mac/Linux)
  • HTTPie - User-friendly command line tool

Complete CRUD Server

Here is a complete server with all HTTP methods:

server.js - Full CRUD API
const http = require('http');

let todos = [
    { id: 1, task: 'Learn Node.js', done: false },
    { id: 2, task: 'Build an API', done: false }
];
let nextId = 3;

// Helper to parse JSON body
function getBody(req) {
    return new Promise((resolve, reject) => {
        let body = '';
        req.on('data', chunk => body += chunk);
        req.on('end', () => {
            try {
                resolve(body ? JSON.parse(body) : {});
            } catch (e) {
                reject(e);
            }
        });
    });
}

// Helper to send JSON response
function sendJson(res, status, data) {
    res.statusCode = status;
    res.setHeader('Content-Type', 'application/json');
    res.end(JSON.stringify(data));
}

const server = http.createServer(async (req, res) => {
    const { method, url } = req;

    // Parse URL to get ID: /api/todos/123 -> 123
    const match = url.match(/^\/api\/todos\/(\d+)$/);
    const id = match ? parseInt(match[1]) : null;

    // GET /api/todos - List all todos
    if (method === 'GET' && url === '/api/todos') {
        sendJson(res, 200, todos);
        return;
    }

    // GET /api/todos/:id - Get single todo
    if (method === 'GET' && id) {
        const todo = todos.find(t => t.id === id);
        if (!todo) {
            sendJson(res, 404, { error: 'Todo not found' });
            return;
        }
        sendJson(res, 200, todo);
        return;
    }

    // POST /api/todos - Create todo
    if (method === 'POST' && url === '/api/todos') {
        try {
            const data = await getBody(req);
            if (!data.task) {
                sendJson(res, 400, { error: 'Task is required' });
                return;
            }
            const newTodo = {
                id: nextId++,
                task: data.task,
                done: false
            };
            todos.push(newTodo);
            sendJson(res, 201, newTodo);
        } catch (e) {
            sendJson(res, 400, { error: 'Invalid JSON' });
        }
        return;
    }

    // PUT /api/todos/:id - Update todo
    if (method === 'PUT' && id) {
        const index = todos.findIndex(t => t.id === id);
        if (index === -1) {
            sendJson(res, 404, { error: 'Todo not found' });
            return;
        }
        try {
            const data = await getBody(req);
            todos[index] = { ...todos[index], ...data };
            sendJson(res, 200, todos[index]);
        } catch (e) {
            sendJson(res, 400, { error: 'Invalid JSON' });
        }
        return;
    }

    // DELETE /api/todos/:id - Delete todo
    if (method === 'DELETE' && id) {
        const index = todos.findIndex(t => t.id === id);
        if (index === -1) {
            sendJson(res, 404, { error: 'Todo not found' });
            return;
        }
        todos.splice(index, 1);
        sendJson(res, 200, { message: 'Todo deleted' });
        return;
    }

    // 404 for everything else
    sendJson(res, 404, { error: 'Not Found' });
});

server.listen(3000, () => {
    console.log('Todo API running on http://localhost:3000');
});

Video Resources

Knowledge Check: Day 3

1. Which HTTP method should you use to create a new resource?

APOST
BGET
CPUT
DDELETE

2. What does JSON.stringify() do?

AParses a JSON string into an object
BValidates JSON syntax
CConverts a JavaScript object to a JSON string
DFormats JSON for display

3. What is the difference between PUT and PATCH?

APUT creates, PATCH updates
BPUT replaces entirely, PATCH updates partially
CPUT is faster than PATCH
DThere is no difference

4. What Content-Type header should you set for JSON responses?

Atext/plain
Btext/html
Ctext/json
Dapplication/json

Day 3 Complete!

You now understand HTTP methods and can build APIs that Create, Read, Update, and Delete data. You also know JSON - the language APIs speak. This CRUD pattern is the foundation of almost every web application.

Tomorrow, we introduce Express.js - a framework that makes building servers much easier and more organized.