Assuming you have an API and you want to convey the types of operations that users can perform at a specific endpoint. You can use external description formats like OpenAPI or JSON Schema, but sometimes it’s also nice to convey this information dynamically on the API itself.<span><span>OPTIONS</span></span> is the method used for this purpose. You might know this HTTP method from CORS, but its general purpose is to allow clients to passively find out, “What can I do here?”.All HTTP clients typically support sending an <span><span>OPTIONS</span></span> request. For example, using <span><span>fetch()</span></span>:
const response = await fetch( 'https://example.org', {method: 'OPTIONS'});
A basic <span>OPTIONS</span> response might look like this:
HTTP/1.1 204 No ContentDate: Mon, 23 Sep 2024 02:57:38 GMTServer: KKachel/1.2Allow: GET, PUT, POST, DELETE, OPTIONS
Based on the <span><span>Allow</span></span> header, you can quickly understand the available HTTP methods at a specific endpoint. Many web frameworks automatically generate and dynamically create a list of methods by route, so you might get this for free.To check if your server does this, try running the following command (replace with your URL):
curl -X OPTIONS http://localhost:3000/some/endpoint/
One nice thing you can do with the <span><span>Allow</span></span> header is that you can also convey access control information at a very basic level. For example, you only include <span><span>DELETE</span></span> and <span><span>PUT</span></span> if the user has write access to the resource.
Accept and Accept-Encoding
In addition to the HTTP standard headers used for discovery, there are a few others. Here’s an example that showcases several:
HTTP/1.1 204 No ContentDate: Mon, 23 Sep 2024 02:57:38 GMTServer: KKachel/1.2Allow: GET, PUT, POST, DELETE, OPTIONSAccept: application/vnd.my-company-api+json, application/json, text/htmlAccept-Encoding: gzip,brotli,identity
You may already be familiar with <span><span>Accept</span></span> and <span><span>Accept-Encoding</span></span> in HTTP requests, but they can also appear in responses. The <span><span>Accept</span></span> in the response allows you to tell the client the available mimetypes at the endpoint. I like to add <span><span>text/html</span></span> to each JSON API endpoint and ensure the API URL can be opened in a browser for easy debugging among developers.
Patching, Posting, and Querying
Patching, Posting, and Querying
There are also three other headers you can use: <span><span>Accept-Patch</span></span>, <span><span>Accept-Post</span></span>, and <span><span>Accept-Query</span></span> . These three headers are used to inform the client about the content types available for the <span><span>PATCH</span></span>, <span><span>POST</span></span>, and <span><span>QUERY</span></span> HTTP methods respectively.
For all these headers, their values effectively determine what is valid. The values are for the <span>Content-Type</span> header when making requests.
HTTP/1.1 204 No ContentDate: Mon, 23 Sep 2024 02:57:38 GMTServer: KKachel/1.2Allow: OPTIONS, QUERY, POST, PATCHAccept-Patch: application/json-patch+json, application/merge-patch+jsonAccept-Query: application/graphqlAccept-Post: multipart/form-data, application/vnd.custom.rpc+json
In the above response, the server indicates that it supports both JSON Patch and JSON Merge Patch content types for <span>PATCH</span> requests. It also implies that GraphQL can be used via the <span><span>QUERY</span></span> method, and that <span><span>POST</span></span> supports standard file uploads and some custom JSON-based formats.
Typically, you won’t find all of these at the same endpoint, but I wanted to provide a few examples together.
Where is PUT?
Strangely, there is no specific header for <span>PUT</span> requests. You could argue that <span>GET</span> and <span>PUT</span> are symmetrical, so perhaps the <span>Accept</span> header kind extends to both. But the specification does not clarify this.
I think the reality is that <span>Accept-Patch</span> is the first header to clearly define this as a feature discovery means regarding <span>OPTIONS</span>. <span>Accept-Post</span> and <span>Accept-Query</span> follow. I believe <span>Accept-Patch</span> is modeled after <span>OPTIONS</span> in the wild, even if HTTP specific does not super clearly define it.
If my explanation here is wrong, I would love to know!
Note: If you want to know about <span>DELETE</span>, <span>DELETE</span> should never have a body, thus, can users need to know that they can delete, which you can see in the <span>Allow</span> header. If this is new, read my other article on <span>GET</span> requests bodies. Most of the information there applies to <span>DELETE</span> as well.
Linking to Documentation
Because the <span>OPTIONS</span> response is also a good place to tell users where to find supplementary documentation. In the example below, I include two machine-readable links to documentation sites, linking to the OpenAPI definition, as well as human-readable information in the response body:
HTTP/1.1 200 OKDate: Mon, 23 Sep 2024 04:45:38 GMTAllow: GET, QUERY, OPTIONSLink: <https://docs.example.org/api/some-endpoint>; rel="service-doc"Link: <https://api.example.org/openapi.yml>; rel="service-desc" type="application/openapi+yaml"Content-Type: text/plainHey there!Thanks for checking out this API. You can find the docs for this specific endpoint at: https://docs.example.org/api/some-endpointCheers,The dev team
I recommend keeping the response minimal and informal; any real information should only exist at its own URL and link to it.
I used <span>service-doc</span> and <span>service-desc</span> link relations here, but you can certainly use any IANA link relation type or customize one. See the Web Linking specification for more information.
Ambiguous Usage
WebDAV Usage
WebDAV, CalDAV, and CardDAV also use <span>OPTIONS</span> for feature discovery. For example:
HTTP/1.1 204 No ContentDate: Mon, 23 Sep 2024 05:01:50 GMTAllow: GET, PROPFIND, ACL, PROPPATCH, MKCOL, LOCK, UNLOCKDAV: 1, 2, 3, access-control, addressbook, calendar-access
Server-Scoped Asterisk Requests
Typically, HTTP requests are sent to a path on the server, the first line looks something like this in HTTP/1.1:
GET /path HTTP/1.1
However, there are some other rarely used “request line” formats. One allows you to discover the available features across the entire server, using an asterisk:
OPTIONS * HTTP/1.1
The asterisk here is not a path. Typically, asterisks are not even allowed in URIs. Many HTTP clients (including <span>fetch()</span><span>) do not even support this request.</span>
Classic web servers like Apache and Nginx should support this. Give it a try using CURL
curl -vX OPTIONS --request-target '*' http://example.org
Final Remarks
If you have reason to allow clients to discover features at an endpoint, consider using <span>OPTIONS</span> instead of proprietary methods! As you can see in many of these examples, using mimetypes is particularly useful.
If you have questions, other novel uses of <span>OPTIONS</span>, or other ideas around feature discovery, feel free to leave a comment:
Source:
https://evertpot.com/discovering-features-with-http-options/