We need to build a music library API that manages artists, albums, and songs. Think of this like creating a digital music catalog system where we need to organize and access different pieces of musical content. This API will handle various operations like adding new artists, retrieving album information, and managing song details.
Before we dive into implementation, let's understand what makes a good API. Just as a well-organized physical library has clear systems for finding and managing books, our API needs clear, consistent patterns for managing music data. Each endpoint should serve a specific purpose, like a librarian who knows exactly where to find any book you request.
const express = require('express');
const app = express();
// Enable JSON parsing for all incoming requests
app.use(express.json());
// Optional debugging middleware to verify request bodies
app.use((req, res, next) => {
console.log('Request Body:', req.body);
next();
});
This setup is like having a universal translator at the entrance of our library. The express.json() middleware translates incoming JSON messages into a format our application can understand, just as a librarian might translate book requests into specific catalog numbers.
// Get all artists - like browsing the library's author catalog
app.get('/artists', (req, res) => {
const artists = getAllArtists();
res.json(artists);
});
// Add a new artist - like adding a new author to the catalog
app.post('/artists', (req, res) => {
const newArtist = addArtist(req.body);
// 201 status code indicates successful creation
res.status(201).json(newArtist);
});
// Get specific artist with their albums - like getting an author's complete works
app.get('/artists/:artistId', (req, res) => {
const artist = getArtistByArtistId(req.params.artistId);
res.json(artist);
});
// Get all albums for an artist
app.get('/artists/:artistId/albums', (req, res) => {
const albums = getAlbumsByArtistId(req.params.artistId);
res.json(albums);
});
// Add a new album for an artist
app.post('/artists/:artistId/albums', (req, res) => {
const newAlbum = addAlbumByArtistId(req.params.artistId, req.body);
res.status(201).json(newAlbum);
});
// Filter albums by starting letter
app.get('/albums', (req, res) => {
const { startsWith } = req.query;
const filteredAlbums = getFilteredAlbums(startsWith);
res.json(filteredAlbums);
});
// Get songs for a specific album
app.get('/albums/:albumId/songs', (req, res) => {
const songs = getSongsByAlbumId(req.params.albumId);
res.json(songs);
});
// Add a new song to an album
app.post('/albums/:albumId/songs', (req, res) => {
const newSong = addSongByAlbumId(req.params.albumId, req.body);
res.status(201).json(newSong);
});
// Edit a song's details
app.put('/songs/:songId', (req, res) => {
const updatedSong = editSongBySongId(req.params.songId, req.body);
res.json(updatedSong);
});
Think of HTTP status codes like the different types of responses you might get from a librarian:
200 (OK): "Here's the book you requested"
201 (Created): "I've added that new book to our collection"
404 (Not Found): "Sorry, we don't have that book"
500 (Server Error): "Our catalog system is currently down"
Our API follows RESTful patterns, which are like the standardized organization systems used in libraries worldwide. For example:
/artists is like the main author catalog
/artists/:artistId/albums is like finding all books by a specific author
/albums/:albumId/songs is like finding all chapters in a specific book
When testing your API endpoints, consider these scenarios:
// Testing GET /artists
// Expected: List of all artists
curl http://localhost:8000/artists
// Testing POST /artists
// Expected: New artist with ID
curl -X POST http://localhost:8000/artists \
-H "Content-Type: application/json" \
-d '{"name": "Led Zeppelin"}'
// Testing GET /artists/:artistId/albums
// Expected: All albums for specific artist
curl http://localhost:8000/artists/1/albums
The album filtering feature demonstrates how to handle query parameters. This is like having a smart search system in our library that can find books based on specific criteria:
// Examples of album filtering
GET /albums?startsWith=S // Finds albums starting with 'S'
GET /albums?startsWith=P // Finds albums starting with 'P'
Throughout our implementation, we've followed several important patterns:
1. Consistent Route Structure: Resources are organized hierarchically
2. Appropriate HTTP Methods: GET for reading, POST for creating, etc.
3. Clear Response Formats: All responses are JSON with consistent structure
4. Status Code Usage: Proper status codes indicate request outcomes
5. Resource Relationships: Artists have albums, albums have songs
Remember: A well-designed API is like a well-organized library - it should be intuitive to use, consistent in its organization, and reliable in its operation. Each endpoint serves a specific purpose, just as each section of a library has its specific type of books.