Menu
CoddyTech

CORS

Part of the REST APIs section of Coddy's Node.js journey. Lesson 20 of 25.

A cross-origin PUT, PATCH or DELETE, or a request with a JSON Content-Type, normally makes the browser ask permission first. This OPTIONS request is a preflight. The response must permit the origin, method and request headers.

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://shop.example.com
Access-Control-Allow-Methods: GET, POST, PATCH, OPTIONS
Access-Control-Allow-Headers: Content-Type

Set Access-Control-Allow-Origin on every response, including the preflight. With one allowed origin, you can send that fixed value on every response: the browser compares it with the page’s origin. Each methods or headers value is one comma-separated string.

For OPTIONS, send 204 and end the response. For other methods, keep the origin header and call next(). Put this middleware first, before express.json() and the routes so error responses have permission too. The request bar can inspect the headers, but only browsers enforce CORS.

challenge icon

Challenge

Easy

This step opens the course’s prepared task tracker API project, rather than your project files from Pagination (including routes/tasks.js). Your earlier work stays in its own lesson. Read the supplied files before editing server.js. This copy contains task CRUD routes, validation, pagination, filters and sorting.

In server.js, before express.json() and the routes, add middleware that permits https://board.example.com. Set Access-Control-Allow-Origin to that exact origin, Access-Control-Allow-Methods to GET, POST, PUT, PATCH, DELETE, OPTIONS, and Access-Control-Allow-Headers to Content-Type. For OPTIONS respond with 204 and end. For other methods call next.

Try it: send OPTIONS /api/tasks/2. You should see 204 and the three permission headers. Send GET /api/tasks: it still returns the task list and the origin header. POST {"title":"Order new chairs"} to /api/tasks still creates a task with 201.

Try it yourself

import express from 'express';
import { sendError } from './errors.js';
import taskRoutes from './routes/tasks.js';

const app = express();
app.use(express.json());

app.use('/api/tasks', taskRoutes);

// Errors from the routes end here. A body that is not valid JSON is the
// client's mistake (400); anything else is ours (500).
app.use((err, req, res, next) => {
    if (err.type === 'entity.parse.failed') {
        return sendError(res, 400, 'invalid_json', 'The body is not valid JSON');
    }
    console.error(err);
    sendError(res, 500, 'server_error', 'Something went wrong');
});

app.listen(3000, () => {
    console.log('Task tracker API on port 3000');
});
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in REST APIs

Practice on your own: Express playground