The internal framework we have at my company directly ties the extension of the endpoint to an expected mimetype return from the controller. So endpoint.html / endpoint.xml / endpoint.json / endpoint.csv you always know what you are getting. Only the implemented extensions work, defined per controller, no magic here.
There is an escape mechanism for making endpoints without an extension but we rarely use it.
It’s a weird design I probably wouldn’t make these days, but for debugging at a glance it’s honestly pretty nice to look at the stream of requests and just know the type of each.
That's an interesting choice. I like that from an ease of use perspective, but I don't love it from the perspective of knowing what you're actually accessing, ie, if it's a .JSON URL I'm expecting to be served a static JSON file rather than a script that's serving me JSON dynamically. I kind of feel the same way about certain uses of HTTP status codes, like, if I get a 404 I would expect it to be because the page wasn't found, not because a POST parameter was wrong. The worst offenders don't serve an error message with the status code, but I'm getting off track here.
That's clearly incorrect semantics, and should be 400 Bad Request. Unfortunately the semantics of HTTP status codes are unenforceable with some obvious exceptions.
There's no excuse for not implementing them properly, however. I'm less of a fan of the existence of verbs, which I consider to be a part of the URI which isn't in the URI itself. Things would be better if one URI was one endpoint, rather than potentially as many endpoints as there are verbs.
There is an escape mechanism for making endpoints without an extension but we rarely use it.
It’s a weird design I probably wouldn’t make these days, but for debugging at a glance it’s honestly pretty nice to look at the stream of requests and just know the type of each.