Express Route Handlers

Understanding the Problem

We need to create a RESTful API using Express.js that handles various operations for artists, albums, and songs. The application needs to:

Core Requirements:

Input Types:

Expected Output:

Devising a Plan

  1. Set up JSON parsing middleware
  2. Implement basic artist routes
  3. Add bonus artist functionality
  4. Create album-related routes
  5. Implement song-related endpoints
  6. Add filtering and complex queries
  7. Test all routes with Postman

Carrying Out the Plan

Basic Setup - JSON Parsing

// Initial setup of Express application
const express = require('express');
const app = express();

// Enable JSON parsing for incoming requests
app.use(express.json());

// Basic debugging middleware
app.use((req, res, next) => {
    console.log('Request Body:', req.body);
    next();
});

Think of JSON parsing middleware like a postal worker who opens envelopes (requests) and organizes the contents (JSON data) into a neat stack (req.body) before delivering it to the intended recipient (your route handlers).

Basic Artist Routes

// Import data functions
const { getAllArtists, addArtist } = require('./data.js');

// GET /artists - Retrieve all artists
app.get('/artists', (req, res) => {
    // Get array of all artists from data layer
    const artists = getAllArtists();
    // Send JSON response
    res.json(artists);
});

// POST /artists - Create a new artist
app.post('/artists', (req, res) => {
    // Extract artist data from request body
    const artistData = req.body;
    // Create new artist using data function
    const newArtist = addArtist(artistData);
    // Send 201 status with new artist data
    res.status(201).json(newArtist);
});

Bonus Routes - Latest Artist

// Import additional functions
const { getLatestArtist, getAlbumsForLatestArtist } = require('./data.js');

// GET /artists/latest - Get most recently added artist
app.get('/artists/latest', (req, res) => {
    const latest = getLatestArtist();
    res.json({ latest });
});

// GET /artists/latest/albums - Get albums of latest artist
app.get('/artists/latest/albums', (req, res) => {
    const albums = getAlbumsForLatestArtist();
    res.json({ latest: { albums } });
});

Advanced Artist Routes

// Import required functions
const {
    getArtistByArtistId,
    editArtistByArtistId,
    deleteArtistByArtistId
} = require('./data.js');

// GET /artists/:artistId - Get specific artist
app.get('/artists/:artistId', (req, res) => {
    const { artistId } = req.params;
    const artist = getArtistByArtistId(Number(artistId));
    res.json(artist);
});

// PUT /artists/:artistId - Update artist
app.put('/artists/:artistId', (req, res) => {
    const { artistId } = req.params;
    const updatedArtist = editArtistByArtistId(Number(artistId), req.body);
    res.json(updatedArtist);
});

// DELETE /artists/:artistId - Remove artist
app.delete('/artists/:artistId', (req, res) => {
    const { artistId } = req.params;
    deleteArtistByArtistId(Number(artistId));
    res.json({ message: "Successfully deleted" });
});

Album Routes

// Import album-related functions
const {
    getAlbumByAlbumId,
    addAlbumByArtistId,
    editAlbumByAlbumId,
    deleteAlbumByAlbumId,
    getFilteredAlbums
} = require('./data.js');

// GET /albums/:albumId - Get album details
app.get('/albums/:albumId', (req, res) => {
    const { albumId } = req.params;
    const album = getAlbumByAlbumId(Number(albumId));
    res.json(album);
});

// POST /artists/:artistId/albums - Create album
app.post('/artists/:artistId/albums', (req, res) => {
    const { artistId } = req.params;
    const newAlbum = addAlbumByArtistId(Number(artistId), req.body);
    res.status(201).json(newAlbum);
});

// GET /albums - Get filtered albums
app.get('/albums', (req, res) => {
    const { startsWith } = req.query;
    const albums = getFilteredAlbums(startsWith);
    res.json(albums);
});

Song Routes

// Import song-related functions
const {
    getSongBySongId,
    addSongByAlbumId,
    getSongsByArtistId,
    editSongBySongId,
    deleteSongBySongId
} = require('./data.js');

// GET /songs/:songId - Get song details
app.get('/songs/:songId', (req, res) => {
    const { songId } = req.params;
    const song = getSongBySongId(Number(songId));
    res.json(song);
});

// POST /albums/:albumId/songs - Add song to album
app.post('/albums/:albumId/songs', (req, res) => {
    const { albumId } = req.params;
    const newSong = addSongByAlbumId(Number(albumId), req.body);
    res.status(201).json(newSong);
});

Looking Back and Understanding

Key Concepts Explained

Route Parameters vs Query Parameters

Think of route parameters like house numbers on a street - they're part of the address itself (e.g., /artists/1). Query parameters are more like special instructions left for the delivery person (e.g., /albums?startsWith=S).

HTTP Methods

We can think of HTTP methods like different types of interactions in a library:

Status Codes

HTTP status codes are like different types of responses you might get at a store:

Common Pitfalls and Tips

Testing Your Implementation

For each endpoint, you can use Postman to test:

  1. Send the request with the specified method and URL
  2. Include any required headers (especially Content-Type for POST/PUT)
  3. Add the appropriate request body for POST/PUT requests
  4. Verify the response status code matches the specification
  5. Check that the response body matches the expected format

Further Learning

To deepen your understanding of Express routing, try these extensions: