Open ejmr opened 8 years ago
It's definitely a valid point and I see that it is part of the HTTP/1.1 specification. I also asked a little bit around and it seems WEBDAV also implemented custom methods. I believe that we should follow the HTTP spec, but not sure how easy it is to support it in general. How are custom methods defined? Are they restricted to have a request/response body, etc. like every other method?
How are custom methods defined? Are they restricted to have a request/response body, etc. like every other method?
Custom methods are defined by the server, which is to say the server has the "authority" to tells clients what is a method and what isn't, which is done using the Allow
response header; it lists all of the methods valid for any given URI. Generally (although not required) OPTIONS
will return the Allow
header, which will be something like...
Allow: OPTIONS, HEAD, GET, PUT
...which clients can use to recognize what methods are allowed for that entity. When a PUT
request creates a new entity the server should (in the RFC 2119 sense) return an Allow
header listing all acceptable methods for that entity; the standard doesn't make this mandatory though. Allow
is the only way a server can tell clients about custom methods. And the only situation where the server must (again RFC 2119) return the Allow
header is when it sends a 405 Method Not Allowed
response, which somewhat ironically makes that the best way for a client to "discover" the existence of a method. I quote "discover" specifically to highlight that the HTTP/1.1 standard, with regard to custom methods, is designed around the idea of both the server and client being ignorant of what methods are available. So those custom methods are "defined" essentially to the extent that they are made discoverable by the server supporting them.
Are they restricted to have a request/response body, etc. like every other method?
Custom methods are required to have the Host
header, which all HTTP/1.1 methods must have, but that's it. They are not required to have a response body, in which case the server would return something like 204 No Content
for a successful request involving a custom method that doesn't produce a response body. But their responses can have bodies, in which case they would have the usual headers describing the content type, etc., to give the client as much information as possible about what the server is sending back.
Thank you @ejmr
No problem. Sometime this week I hope to write an example of what I think a custom method definition in RAML would look like using my own use-case as an example, and then see what challenges I run into hacking support for that into one or two tools. Can't guarantee I'll get it done, but that's high on my list of "stuff to do when I have free time to kill", heh.
that would be cool - post that here for everyone to decide if that goes into the spec officially. @usarid for you visibility.
Here's a brainstorming example I came up with.
#%RAML 1.0
title: Example of a custom HTTP method
mediaType: application/json
types:
Player:
type: object
properties:
id: number
name: string
position: number
/players/{id}:
# The "allow" property provides a definition for the `Allow`
# header which the server might return if given the `OPTIONS`
# method, and which it *MUST* return when given any method that
# results in a 405 Method Not Found response.
#
# This list also describes in RAML which methods are valid for this
# resource. In this example we define a non-standard `RESET`
# method.
allow:
- options
- head
- get
- put
- delete
- reset
get:
responses:
200:
application/json:
type: Player
options:
responses:
200:
headers:
Allow: OPTIONS, HEAD, GET, PUT, DELETE, RESET
# The `POST` method is not listed as an allowed method in the list
# above. Therefore, in accordance with the HTTP/1.1 standard, the
# server *MUST* return a 405 Method Not Found which *MUST* include
# the `Allow` header, just as the header was defined for `OPTIONS`.
# A smart RAML processor could take the `allow` list and generate
# the the `Allow` response header for all 405 responses
# automatically.
post:
responses:
405:
# Automatically generated based on `allow`...
#
# headers:
# Allow: OPTIONS, HEAD, GET, PUT, DELETE, RESET
# If a `PUT` request creates a new resource then the server must
# return a 201 Created response. That response can (but is not
# required to) include an `Allow` header describing the methods
# available on the new resource. Again, a RAML tool which sees the
# `allow` property for this URI could implicitly define that header
# for a 201 Created response.
put:
responses:
202:
# Implicitly includes the `Allow` header.
204:
# It would not be incorrect to implicitly define the header
# for this response either.
# Other standard methods omitted for brevity...
# Our non-standard method. HTTP/1.1 gives custom methods the
# freedom to accept and return whatever they want. The `Host`
# header is the only header which all methods *MUST* accept. RAML
# already describes this header implicitly in the form of base URIs
# and resource definitions themselves; and an HTTP server which
# doesn't handle `Host` is flat-out broken and unusable anyway, so
# we have no need to explicitly define that request header here.
#
# Responses for custom methods are not required to have a body, and
# this example does not, which is why it returns 204 No Content.
reset:
responses:
204:
+1 to this, we're also internally using custom methods.
It seems relevant to point out that HTTP/1.1 methods are case-sensitive and defined using the "token" production; see details in the EBNF:
tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
"^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
token = 1*tchar
While I've not seen anyone using or proposing a method that doesn't use SHOUTY-CAPS, and there's precedent for using lower-cased versions of method names when referring to methods (as in HTML <form method="...">
), not using method names as they really exist in HTTP seems a bad idea.
My inner pedant says we should end up using GET, PATCH, POST, etc., in RAML documents, though my hatred for the shift key makes me like the lower-cased names better, so I'm a little torn.
First please see my comments on #95. The HTTP/1.1 specification allows servers to implement arbitrary methods but these are not possible to describe in RAML 0.8. Here is a personal use-case for defining new HTTP methods. I wanted to use RAML for that project, but as it is the lack of support for arbitrary HTTP methods made it impossible to use.
Ignoring my own use-case though, in general I think it is a mistake for RAML to restrict support for HTTP methods in any way, e.g. supporting only a fixed list of methods. This puts RAML in contrast with section 5.1.1 of the HTTP/1.1 standard, making it impossible to describe certain APIs with RAML which are perfectly acceptable and valid under RFC 2616.
I have not yet tried modifying one of the various RAML tools to patch in support for arbitrary HTTP methods though, so I don't have a technical solution to present at the moment. My general idea is that wherever RAML allows things like
/get
or/post
, it should accept/foo
wherefoo
could be any name that could be a valid HTTP method name.