← Back to all tutorials

GET Requests

Implement GET endpoints to retrieve data from MongoDB — fetch all documents, find by ID, filter with query parameters, and paginate results.

GET Requests

GET requests are the most common in any API — they retrieve data without modifying it. In this episode you will implement comprehensive GET endpoints that fetch all ninjas, find individual ninjas by ID, filter by query parameters, and paginate large result sets.

GET All Documents

router.get('/', async (req, res, next) => {
    try {
        const ninjas = await Ninja.find();
        res.json(ninjas);
    } catch (err) {
        next(err);
    }
});

Ninja.find() without arguments returns all documents in the collection. For large collections, this can be slow — pagination (covered below) limits the results.

GET a Single Document by ID

router.get('/:id', async (req, res, next) => {
    try {
        const ninja = await Ninja.findById(req.params.id);
        if (!ninja) {
            return res.status(404).json({ error: 'Ninja not found' });
        }
        res.json(ninja);
    } catch (err) {
        next(err);
    }
});

Filtering with Query Parameters

// GET /api/ninjas?rank=5&available=true
router.get('/', async (req, res, next) => {
    try {
        const filter = {};
        if (req.query.rank) filter.rank = req.query.rank;
        if (req.query.available) filter.available = req.query.available === 'true';

        const ninjas = await Ninja.find(filter);
        res.json(ninjas);
    } catch (err) {
        next(err);
    }
});

Sorting

// GET /api/ninjas?sort=rank or ?sort=-rank (descending)
const ninjas = await Ninja.find(filter).sort(req.query.sort || '-createdAt');
ValueOrder
'rank'Ascending (1, 2, 3...)
'-rank'Descending (10, 9, 8...)
'rank name'Sort by rank, then by name

Pagination

// GET /api/ninjas?page=2&limit=10
router.get('/', async (req, res, next) => {
    try {
        const page = parseInt(req.query.page) || 1;
        const limit = parseInt(req.query.limit) || 10;
        const skip = (page - 1) * limit;

        const ninjas = await Ninja.find(filter)
            .sort('-createdAt')
            .skip(skip)
            .limit(limit);

        const total = await Ninja.countDocuments(filter);

        res.json({
            data: ninjas,
            pagination: {
                total,
                page,
                limit,
                pages: Math.ceil(total / limit),
            },
        });
    } catch (err) {
        next(err);
    }
});
MethodPurpose
.skip(n)Skip the first n documents
.limit(n)Return at most n documents
.countDocuments()Count total matching documents (for pagination metadata)

Selecting Specific Fields

// Only return name and rank
const ninjas = await Ninja.find().select('name rank -_id');

// Exclude a field
const ninjas = await Ninja.find().select('-__v');

Key Takeaways

  • find() returns all documents; findById() returns one by its _id
  • Pass a filter object to find() to match specific field values
  • .sort(), .skip(), and .limit() chain together for sorted, paginated results
  • Include pagination metadata (total, page, pages) so clients know how many pages exist
  • Use .select() to control which fields are returned