Discovering features using HTTP OPTIONS – Evert Pot

Say you have an API, and you want to communicate what sort of things a user can
do on a specific endpoint. You can use external description formats like OpenAPI
or JSON Schema, but sometimes it’s nice to also dynamically communicate this on
the API itself.

OPTIONS is the method used for that. You may know this HTTP method from
CORS, but it’s general purpose is for clients to passively find out ‘What
can I do here?’.

All HTTP clients typically support making OPTIONS request. For example with
fetch():

const response = await fetch(
https://example.org,
{method: OPTIONS}
);

A basic OPTIONS response might might look like this:

HTTP/1.1 204 No Content
Date: Mon, 23 Sep 2024 02:57:38 GMT
Server: KKachel/1.2
Allow: GET, PUT, POST, DELETE, OPTIONS

Based on the Allow header you can quickly tell which HTTP methods
are available at a given endpoint. Many web frameworks emit this automatically
and generate the list of methods dynamically per route, so chances are that you
get this one for free.

To find out if your server does, try running the command below (with your
URL!):

curl -X OPTIONS https://localhost:3000/some/endpoint/

One nice thing you could do with the Allow header, is that you could also
communicate access-control information on a very basic level. For example,
you could only include DELETE and PUT if a user has write access to
a resource.

Accept and Accept-Encoding

There’s server other standard headers for discovery. Here’s an example showing
a few at once:

HTTP/1.1 204 No Content
Date: Mon, 23 Sep 2024 02:57:38 GMT
Server: KKachel/1.2
Allow: GET, PUT, POST, DELETE, OPTIONS
Accept: application/vnd.my-company-api+json, application/json, text/html
Accept-Encoding: gzip,brotli,identity

You may already be familiar with Accept and Accept-Encoding from
HTTP requests, but they can also appear in responses. Accept in a response
lets you tell the client which kind of mimetypes are available at an endpoint.
I like adding text/html to every JSON api endpoint and making sure that
API urls

Truncated by Planet PHP, read more at the original (another 11304 bytes)