hectoday
DocsCoursesChangelog GitHub
DocsCoursesChangelog GitHub

Access Required

Enter your access code to view courses.

Invalid code

← All courses HTTP from scratch

What is HTTP

  • The request-response model
  • Anatomy of an HTTP request
  • Anatomy of an HTTP response

Methods

  • GET and HEAD
  • POST
  • PUT, PATCH, and DELETE
  • OPTIONS and CORS preflight

Status codes

  • 2xx success
  • 3xx redirection
  • 4xx client errors
  • 5xx server errors

Headers

  • Request headers
  • Response headers
  • Custom headers

The body

  • JSON
  • Form data and multipart
  • No body

Connections

  • TCP, DNS, and TLS
  • HTTP/1.1 vs HTTP/2
  • Cookies and state

Putting it all together

  • Building a server from scratch
  • From scratch to framework

OPTIONS and CORS preflight

A method you never call yourself

All the methods we have covered so far (GET, POST, PUT, PATCH, DELETE) are ones you use directly when building an API. OPTIONS is different. You will almost never call it yourself, but your browser calls it all the time behind the scenes. Understanding what it does will save you hours of confusion the first time you hit a CORS error.

What OPTIONS does

OPTIONS asks the server a simple question: “What am I allowed to do with this resource?”

OPTIONS /books HTTP/1.1
Host: api.example.com
HTTP/1.1 204 No Content
Allow: GET, POST, OPTIONS

The Allow header in the response lists which methods the server supports for /books. That is it. OPTIONS does not change anything, does not return any data. It is purely an inquiry.

Most frameworks handle OPTIONS automatically. You probably will not write OPTIONS handlers yourself. But browsers use OPTIONS in a very specific, very important way.

The same-origin policy

To understand why OPTIONS matters, we need to talk about a browser security rule called the same-origin policy.

Browsers have a rule: JavaScript running on https://myapp.com can only make requests to https://myapp.com. If your JavaScript tries to call https://api.example.com, the browser blocks it. This sounds restrictive, and it is, on purpose.

Two URLs have the same “origin” if they share the same protocol (https), host (myapp.com), and port (443). So https://myapp.com and https://api.example.com have different hosts, which means different origins.

Why does this rule exist? Imagine you are logged into your bank at https://your-bank.com. Without the same-origin policy, a malicious page at https://evil.com could run JavaScript that makes requests to https://your-bank.com using your cookies. It could read your account balance, transfer money, anything your browser is authorized to do. The same-origin policy prevents this.

CORS: the exception to the rule

But here is the problem. Your frontend at https://myapp.com legitimately needs to call your API at https://api.example.com. They are on different origins, and the browser would block it.

CORS (Cross-Origin Resource Sharing) is the mechanism that allows this. The server sends special headers telling the browser: “It is okay for myapp.com to call me.”

Access-Control-Allow-Origin: https://myapp.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization

When the browser sees these headers, it says “the server gave permission” and allows the request to go through.

The preflight request

Here is where OPTIONS comes back in. For certain kinds of cross-origin requests (requests with custom headers like Authorization, or methods like PUT and DELETE), the browser does not just send the request. It sends an OPTIONS request first, called a preflight.

OPTIONS /books HTTP/1.1
Host: api.example.com
Origin: https://myapp.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization

The browser is asking: “Can myapp.com send a POST to /books with Content-Type and Authorization headers?” It asks before sending the real request. Think of it as the browser saying “let me check if this is allowed before I actually do it.”

If the server responds with the right CORS headers, the browser proceeds with the actual POST request. If the server does not, the browser blocks everything and your JavaScript gets a CORS error.

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://myapp.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

That Access-Control-Max-Age: 86400 header is a nice optimization. It tells the browser: “You do not need to send a preflight for the next 24 hours. Cache this permission.” Without it, the browser would send a preflight before every single cross-origin request.

[!NOTE] The Securing Your API course covers CORS configuration in detail. This lesson explains the HTTP mechanism behind it: the OPTIONS preflight request and the Access-Control headers.

Simple requests skip the preflight

Not every cross-origin request triggers a preflight. Simple requests skip it. A request is “simple” if it uses GET or POST, has no custom headers, and the Content-Type is text/plain, application/x-www-form-urlencoded, or multipart/form-data. For these, the browser sends the request directly with an Origin header, and the server responds with Access-Control-Allow-Origin.

But most API requests are not “simple.” The moment you use Content-Type: application/json or include an Authorization header (which is almost always), the browser sends a preflight. So in practice, if you are building a JSON API, expect preflights.

That wraps up HTTP methods. We know how to read (GET, HEAD), create (POST), update (PUT, PATCH), delete (DELETE), and how browsers check permissions (OPTIONS). The next section covers the numbers the server sends back to tell you what happened: status codes.

Exercises

Exercise 1: Open your browser’s developer tools. Make a cross-origin API call from JavaScript. Look in the Network tab for the preflight OPTIONS request.

Exercise 2: Remove the CORS headers from your server. Make a cross-origin request from the browser. Read the CORS error in the console.

Exercise 3: Add Access-Control-Max-Age: 3600 to your CORS headers. Make two requests in a row. Verify the preflight only happens on the first one.

Why does the browser send a preflight OPTIONS request before some cross-origin requests?

← PUT, PATCH, and DELETE 2xx success →

© 2026 hectoday. All rights reserved.