How order works?

Did you mean, “rate_limit is placed between method and rewrite"? If so, that would be correct.

Handler order is also elaborated on in the JSON docs:

The list of handlers for this route. Upon matching a request, they are chained together in a middleware fashion: requests flow from the first handler to the last (top of the list to the bottom), with the possibility that any handler could stop the chain and/or return an error. Responses flow back through the chain (bottom of the list to the top) as they are written out to the client.

Not all handlers call the next handler in the chain. For example, the reverse_proxy handler always sends a request upstream or returns an error. Thus, configuring handlers after reverse_proxy in the same route is illogical, since they would never be executed. You will want to put handlers which originate the response at the very end of your route(s). The documentation for a module should state whether it invokes the next handler, but sometimes it is common sense.

Some handlers manipulate the response. Remember that requests flow down the list, and responses flow up the list.

For example, if you wanted to use both templates and encode handlers, you would need to put templates after encode in your route, because responses flow up. Thus, templates will be able to parse and execute the plain-text response as a template, and then return it up to the encode handler which will then compress it into a binary format.

If templates came before encode, then encode would write a compressed, binary-encoded response to templates which would not be able to parse the response properly.

The correct order, then, is this:

[
    {"handler": "encode"},
    {"handler": "templates"},
    {"handler": "file_server"}
]

The request flows :down_arrow: DOWN (encodetemplatesfile_server).

  1. First, encode will choose how to encode the response and wrap the response.

  2. Then, templates will wrap the response with a buffer.

  3. Finally, file_server will originate the content from a file.

The response flows :up_arrow: UP (file_servertemplatesencode):

  1. First, file_server will write the file to the response.

  2. That write will be buffered and then executed by templates.

  3. Lastly, the write from templates will flow into encode which will compress the stream.

If you think of routes in this way, it will be easy and even fun to solve the puzzle of writing correct routes.

If you want help understanding handler order, I would recommend running caddy adapt –pretty to see the JSON structure, I think that helps a lot.

You can also refer to this wiki article for more information about composing routes: