I'd like to be able to pass in preference as part of the body of the request, like "from", "size", "_source", "query", etc., but it appears that is not an option. Why?
In the case of Kibana it allows a single piece of code to direct all requests from a user to the same choice of replica. This helps hit warm caches.
Multiple parts of Kibana create different request bodies so I can see that having the routing logic in the header helps keeps these responsibilities separated. The same is true of "timeout" settings - these are typically global policies, regardless of request bodies.
I'm not sure I'm following the "this needs to be a global policy" logic because if I want to always just keep my endpoint as "_search", I can't do this if I have to dynamically build the "preference" parameter to have a user-session id; it's the same type of thing that I'd build based upon other parts of the request body, such as "from" or "query", so I guess I'll ask: why can't preference go in the request body?
I'm guessing the analogy might be the post office not wanting to open your mail.
It just stamps any routing info on the envelope when delivering the mail.
It's also why the bulk indexing API puts routing info like index name and doc ID on a line separate from the JSON body - it helps avoid an unnecessary parsing of content being routed for delivery.