Live data from Hacker News

Microsoft REST API Guidelines

github.com

131–140 of 149 posts

Re: Microsoft REST API Guidelines

#131
post #98

Earlier quoted context omitted.

Is that a failure of the people or failure of the spec?

Failure of people and tools. Like the sibling comment says, often tools designed to consume HTTP will throw a more severe class of error upon 4xx/5xx, which then changes the codepath significantly, making it more difficult for the programmer to treat 2xx and 4xx/5xx responses similarly for parsing out the headers and the response body. Web browsers are also guilty of some of these behaviors. They would inject a 'user…

Together, these forces combined to drive some APIs to respond with a 200 for any response.

I once had to work on such an API, which was designed that way because of similar limitations in the (third-party?) iOS networking library used by the app that connected to the API (as it was in 2013, anyway).

One can see how thinking of an HTTP request as an RPC rather than a REST request/response would justify throwing an error instead of returning an object, but since REST is now more common than RPC, one would at least expect an option not to throw.

Re: Microsoft REST API Guidelines

#132

Funny thing: I've been thinking a bit about API versioning quite a bit lately, and the best solution I've come up with is the ONE thing not at all covered in this: put an `api-version` header into the request. I've seen both of the schemes recommended here, and I like neither very much. So what's wrong with my (header) solution?

An API version in an URI is fine. But better would be to use a new domain, if the API brakes backward compatibility entirely.

If the API does not break the clients entirely, just have new resources for incompatible formats:

  /user
  /user2
For the first resource, you can just add a "X-Deprecated" header with a link to the deprecation information. If you already know the date when the resource is abandoned, you can also add a header that has a date of removal in it. If removed, you can either have /user serve the new format or have it serve a HTTP 303 to the new format.

Re: Microsoft REST API Guidelines

#133
post #51

Earlier quoted context omitted.

POST /users/{id}/avatar ? What additional guidance would you expect?

You can turn the uploaded image into base64 string in the client and then just post it as part of your JSON payload.

This is what I've been doing and it's very simple for both client apps and on the server. I don't know if this is feasible for larger files tho.

Re: Microsoft REST API Guidelines

#134

Being that guy again, (and sacrificing my karma) but... This is not REST, it contains nothing about hypermedia, entities having knowledge of their URIs, or any way of discovering features of an API programmatically. While I'm sure there's plenty of good stuff in here (it looks otherwise fairly comprehensive), APIs will continue to be a disparate system that requires custom code for every integration until we can embr…

No worries. There are people out there, like me, who agree with you. You have my vote on this.

Lets say Microsoft at least created their own format, that allows some discovery. That is a good approach, because a big upfront design can be harmful. There are few decisions in HTML you can take as an example.

I am currently working on having a format for my company, that is based on Siren. Its no easy thing to do, because I want it to be easy to be used (which is not simple).

Re: Microsoft REST API Guidelines

#135
post #90

Earlier quoted context omitted.

No there isn't, a great deal of the web is loaded without direct human requests. For example: * Web crawlers * Archival services * Embedded resources (stylesheets, JavaScript, images) * Newsfeeds

All those examples are hard coded algorithms in the bulk copy category. They pretty much just use the GET method to download all or a specific subset of a site. To truly drive a REST API requires a human or an AI. The AI doesn't need to be human equivalent, just smart enough to inteligently interpret the hypermedia. If the API changes the AI would be able to adapt. I'm talking about the complexity of the computer on…

You don't need an AI. A client for automated interaction will hard-code assumptions about content rather than URIs. If the client cannot find a link inside a document, it should just throw an error. A good service would keep links as long as possible, even when deprecated or provide redirects to new resources.

A client for human interaction though (like a native application or a SPA), can just implement the visitor pattern to display the UI.

Instead of moaning about the architecture principles, we must implement solutions / examples of how to write good clients against REST-based services!

Re: Microsoft REST API Guidelines

#136

Earlier quoted context omitted.

Neither of the schemes mentioned here are good as they change the URI for a resource, which breaks all sorts of things. Could you imagine if every website wanting to switch from HTML 4 to HTML 5 had to update their URIs from https://www.example.com/HTMLv4/contact.html to https://www.example.com/HTMLv5/contact.html ? It would be chaos. For instance, if client application A talks to the service using version 1.0 of the…

The "?api-version" approach in the doc is there for exactly the reason you call out. Azure uses this approach. By omitting "/v1.0" from the path it makes the actual URL's far more durable, as they're not version dependent. There are pros and cons to this, as there is with everything. In Azure's case it's great, as you can then use URLs as resource identifiers and put ACL's on them. If they were versioned via the path…

One slight downside of a custom header to specify a version is that OPTIONS calls don't include the value of the custom header, so your pre-flight gets to say yes or no without knowing what version is being called. Putting API version in the URL or query string fixes this.

As for bookmarking a GET request, this is /almost/ doable even following the MSFT guidelines since it says that service implementors MUST also provide a query-string alternative to required custom headers (section 7.8), and that service implementors MUST support explicit versioning. The only fly in this ointment is that the versioning part of the spec only offers two places of specifying the version - URL and query string, and seems to leaves no room for other options.

Personally, I think the Accept header flavor with custom MIME types is the most flexible for minor (backwards compatible) version - see GitHub's API for an example - but it certainly isn't the most simple to work with, neither in client libraries, Curl/WGet command-line use or API consumer tools (almost none let you fiddle with Accept headers). Since API ease of use is such a big factor for adoption, passing versions in the URL or the query string is most likely an OK lowest common denominator for APIs that seek the widest possible reach.

Re: Microsoft REST API Guidelines

#137
post #63

Earlier quoted context omitted.

You're thinking of 'multipart/form-data' with a content-disposition of 'attachment', which is the usual way of uploading binary blobs to a controller resource. But conceivably you could have controllers that accept a PUT or a POST of an 'image/jpeg'. Why wouldn't you, if you're aiming for image uploads?

You're right, I had the wrong MIME type. It's been ages since I was working with this stuff. To answer your second question: because I simplified the example. We run a health insurance website and we need to support life changes events either with or without supporting documentation. It makes no sense to have two separate controllers, as that would mean you could have a successful file attached to an errored-out life…

I agree with you, though I'd say that's mostly a problem of JSON, which doesn't cleanly support binary data, not REST itself. Still, base64 ain't so bad, it's only a 33% increase over raw bytes.

Re: Microsoft REST API Guidelines

#138
post #127

Earlier quoted context omitted.

The problem isn't for simple inconsequential queries like: '$filter=productName eq cupcakes' it's as soon as you expose an OData endpoint you're exposing the entire OData query surface area in which you have no idea what complex expressions consumers will decide to execute (unless you are the only consumer), so you're left supporting them all and coupling to the OData server implementation for life. If your API only…

The problem with just exposing '?productName=cupcakes' is you're assuming just one filter with simple equality. If you need to expose something even just a little more complex, i.e. "A=1 or B=2", or something other than equality like "A>1" or "B!=2", then you quickly find yourself re-implementing a little expression language, syntax for literals, etc. It is a slippery slope, which one can happily go down and succeed…

You never need to drop down into free form expressions to satisfy a query which should never be exposed over a service boundary, this is a very clear Services anti-pattern introducing unnecessary coupling. Find which requirements your Service needs to implement and expose them under the most intuitive self-descriptive label for end users, if you need Orders after a certain date you can expose `?createdAfter=...` or `createdBefore=...`, `?createdAt=...`, etc.

There's nothing in OData that cannot be done more simply and elegantly without it, if you wan't auto querying check out the approach used in: https://github.com/ServiceStack/ServiceStack/wiki/Auto-Query

It's cleaner, faster, more interoperable and it's implementation is fully substitutable, supporting multiple data sources over a user configurable Surface Area that as it's just the same as any other ServiceStack Service has access to all its existing features it enables for all Services including support for an end-to-end typed API over multiple data formats, that's able to take advantage of existing metadata services, and also includes an optional AutoQuery UI. Because it's just another Service there's also infinitely less incremental knowledge to learn whilst at the same time being able to take advantage of features of existing Services Users already know.

This is just one approach, most people never need the inherent complexity and ridgity in big heavy fx's like OData which used to have traction when MS had all its marketing momentum behind it but it's hey day is over and abandoned by its high profile early adopters, now it just lingers in maintenance-mode, mostly forgotten outside of MS and held on by the few that haven't moved on.

Re: Microsoft REST API Guidelines

#139

Earlier quoted context omitted.

The advantage is that there is some level of standardization. 404? That means the entity doesn't exist. 302? I should look somewhere else. 401? The server doesn't know who I am. Accept? I can specify the format. ETag? I can get a faster response if I include the token in the next request. This stuff is really, really common, and people can learn your API very quickly. A transparent caching server can improve performa…

The time spent reading that 404 in this case means "the object ID isn't found" versus "this path doesn't exist" pretty much negates any benefit - you still have to include sub codes. Same for "access denied because token expired" vs "invalid token". Not mention all the stuff that'll get crammed into 400/500/503. If your app is simple enough that all errors map 1:1 to HTTP, great. Or if it doesn't need that level of e…

So, you just want to explain the error further? Wonderful. RFC2616

> the server SHOULD include an entity containing an explanation of the error situation

---

The 3-digit status code tells consumers (1) the status category (success, redirect, client error, server error) and (2) a more specific status within that category. It does that in a way that doesn't require me turning to your API docs every 3 seconds.

Re: Microsoft REST API Guidelines

#140

Earlier quoted context omitted.

Big +1 to killing offset in favor of order-by and an "after" or "before" criteria. However, -1 to the idea of sticking any important "metadata" in headers. For one, it's dramatically easier to interact with response bodies than headers at the terminal or with simple programming libraries and tools. Having only one way of representing data requires fewer special cases. JSON is far superior to key/value pairs in terms…

How do you feel about using StatusCodes to return api information. /tacos/8 ... not found 404 vs { "meta":{ "errors":["not found"] } } or something like that without getting into the form of the JSON returned.

That's exactly the way to do it. Returning the HTTP status code in the body of the message is just wrong.
Post reply on HN