I'm exposing an HTTP API through Play, and in order to manage compatibility-breaking changes, the URL contains the version number. At present this looks like the following:
GET /api/v1/someMethod com.foo.Api.someMethod()
As I introduce a change to the output of one of the methods, I'd like to support v2. For most of the methods though, the behaviour is identical, so I don't care which version is used. I tried to modify the above line to:
GET /api/v:version/someMethod com.foo.Api.someMethod()
But Play fails to compile this, with the error Missing parameter in call definition: version.
I know I didn't use the version parameter in the call - because I didn't need to! Is there a sensible way to achieve what I'm after here, either to get Play to skip this check, or to put a wildcard in the route that is not captured as a parameter?
(I suppose if not I could add the parameter to the method definition, and then ignore it. But I'd rather avoid that if possible.)
Having played around with this for a while trying to find workarounds, I suspect it may not be possible.
The big sticking point is reverse routing. Play wants it to be possible for me to be able to use #routes.com.foo.Api.someMethod in my templates, and have it resolved to the URL that would invoke that method. (And in fact I do this in my API docs). If either of my above proposals were to be accepted, it would be arbitrary what the actual URL was that corresponded to the method.
I suppose what I really want is for the method to have a canonical URL, but for other similar patterns to be considered a match too. I accept that Play does not offer this as part of the relatively simple routes file syntax, and I'd have to accomplish it myself (e.g. by using two patterns, with the wildcard one ultimately but not directly invoking the same method).
Related
I wrote a small cdk construct that parses the logs in a cloudwatch log group via a lambda and sends a mail when a pattern is matched. This allows a developer to be notified via an sns topic, should an error appear in the logs.
The construct needs to know which log group to monitor, and which pattern to look for. These are currently passed in as parameters to its constructor. The user of my small construct library is supposed to use this construct as part of his stack. However, one could also define them as parameters, or better yet given what the docs say values in a context - basically using this construct in a standalone app.
Would this be an appropriate use of the context? What else it is useful for?
It's hard to say a definitive answer, but I would recommend always passing in properties to a construct explicitly on the constructor.
A) This creates consistency with the rest of the constructs.
B) Nothing is 'hidden' in your construct definition.
The only thing I've generally found context useful for is passing in parameters from the CLI, but even that is pretty rare and there are often better ways to do it.
Using expressjs term route parameters to show my problem, I also see people call that path parameters. The "proper" URL will be
Route path: /users/:userId/books/:bookId
But currently I am taking over a project that design the api like this,
/:userId/:bookId
/:groupId/:userId/some_resurce
...
The obvious problem is when I look at the url from browser I will feel confused with what those parameters mean, like the following. But the project has run for more than one year, I need to know whether it is worth the effort to rewrite it.
So is there other problem with the URL like these ?
So is there other problem with the URL like these ?
They might be making extra work for your operators when reading the access logs?
REST doesn't care about URI spelling conventions - until you get to the origin server, a URI is effectively an opaque string; only the origin server has the authority to decompose the URI into its semantic parts.
Which is to say, general purpose components don't care that there are identifiers encoded into the path, or that the semantics of those identifiers changes depending on other path elements.
In particular, they don't care at all that unrelated identifiers have common elements:
/1/2
/1/2/some_resource
As far as a general purpose component is concerned, the resources identified here have no special relationship to one another. (For example, if you DELETE /1/2, that's not expected to impact /1/2/some_resource in any way).
when I look at the url from browser I will feel confused with what those parameters mean
Yup - this is your primary argument: that the current URI design doesn't consider human affordances.
Unless you can make a case that those human focused considerations (users, operators, tech writers) offset the costs of change, you are probably stuck with it.
I want to retrieve all installations that weren't removed yet.
Should I do this like that:
/installations?removedOn=
or
/installations?removedOn=null
or maybe in some other way?
/installations?removed=false
Despite the fact, that something tells me that removed=false looks better, removedOn` may be more practical because later I could query installations that are removed in particular timeframe using the same param.
REST doesn't care what spelling you use for your URI.
/installationsThatArentRemovedYet
/installations?neverRemoved
/f784d74e-b8bf-4832-9297-03816e5b4936
Any of these are fine, as far as REST is concerned.
It follows that these are also fine
/installations?removedOn=
/installations?removedOn=null
/installations?removed=false
One important thing to keep in mind is that the URI should still work even if your underlying implementation changes. So you want stable semantics, with your controller having the responsibility of mapping those semantics to your current implementation.
By convention, REST methods should be nouns and should answer the question "What?" rather than "How?".
So, given that I only need to make find-by-id method, I can easily come up with the RESTful path /foo/{id}, where the part in brackets is substituted by some number.
Now, I also need to add find-by-name method, but I cannot use /foo/{name} as it's already taken.
I cannot also add 'name'-section to the path (i.e. the path would look like /foo/name/{name}), because it would mean "This method returns Foo's name".
What can be an appropriate way to compose this path?
There's nothing wrong with having both /foo/{name} and /foo/{id}. URI semantics are transparent to REST. Trying to embed behavior in URI doesn't make much sense in REST, where that behavior is supposed to come from the media type, the URI merely gives its location. /foo/name/{name} doesn't mean "this method returns Foo's name". It means whatever the source of the hyperlink giving you that URI template says it does.
The appropriate way to do what you want is having /foo returning an hyperlink title "Find Foo by name" or something like that. This hyperlink can be an URI template that when expanded with the name will retrieve a search result with the desired Foo, if it exists.
That uritemplate can be /foo/{name}, /foo?name={name}, /search?type=foo&name={name}, or even something totally unrelated like /my/api/is/a/mess?name={name}. It doesn't really matter, because all the client will do is retrieve that uritemplate, expand it, and retrieve the resource.
Obviously, you're encouraged to think carefully about your paths and make them meaningful and intuitive to client developers, but adopting one or other style doesn't make your API more or less RESTful and you can't say it's more or less appropriate. If you're thinking too much about that, it's probably because you're API is not hypertext driven, and not RESTful at all. Other implementation details, like your framework, will probably have more of a voice on the degree of appropriateness of one or the other than the REST constraints. For instance, some frameworks may have trouble with routing to both foo/{name} and /foo/{id}, but as I said above, that's not a problem at all for REST.
I guess the right way to it is smt like
/foo?name=bar
By querying in this way you will be able return several foo with same name. If for one name there are always no more than one foo perhaps name should be your id.
Is there a built-in way to get at POST/GET parameters in Racket? extract-binding and friends do what I want, but there's a dire note attached about potential security risks related to file uploads which concludes
Therefore, we recommend against their
use, but they are provided for
compatibility with old code.
The best I can figure is (and forgive me in advance)
(bytes->string/utf-8 (binding:form-value (bindings-assq (string->bytes/utf-8 "[field_name_here]") (request-bindings/raw req))))
but that seems unnecessarily complicated (and it seems like it would suffer from some of the same bugs documented in the Bindings section).
Is there a more-or-less standard, non-buggy way to get the value of a POST/GET-variable, given a field name and request? Or better yet, a way of getting back a collection of the POST/GET values as a list/hash/a-list? Barring either of those, is there a function that would do the same, but only for POST variables, ignoring GETs?
extract-binding is bad because it is case-insensitive, is very messy for inputs that return multiple times, doesn't have a way of dealing with file uploads, and automatically assumes everything is UTF-8, which isn't necessarily true. If you can accept those problems, feel free to use it.
The snippet you wrote works when the data is UTF-8 and when there is only one field return. You can define it is a function and avoid writing it many times.
In general, I recommend using formlets to deal with forms and their values.
Now your questions...
"Is there a more-or-less standard, non-buggy way to get the value of a POST/GET-variable, given a field name and request?"
What you have is the standard thing, although you wrongly assume that there is only one value. When there are multiple, you'll want to filter the bindings on the field name. Similarly, you don't need to turn the value into a string, you can leave it as bytes just fine.
"Or better yet, a way of getting back a collection of the POST/GET values as a list/hash/a-list?"
That's what request-bindings/raw does. It is a list of binding? objects. It doesn't make sense to turn it into a hash due to multiple value returns.
"Barring either of those, is there a function that would do the same, but only for POST variables, ignoring GETs?"
The Web server hides the difference between POSTs and GETs from you. You can inspect uri and raw post data to recover them, but you'd have to parse them yourself. I don't recommend it.
Jay