Live data from Hacker News

Microsoft REST API Guidelines

github.com

121–130 of 149 posts

Re: Microsoft REST API Guidelines

#121
post #81

Earlier quoted context omitted.

I recently had the misfortune to have to tackle oData to talk to Dynamics CRM. The choice was between that and SOAP so it was the lesser of two evils. But compared to the other nice, modern REST API's I'm used it smelt of mould and enterprisey cobwebs. I'd have preferred an old school RPC API over that. At least API's that abuse REST from that direction tend to have the virtue of simplicity.

For that matter, I know it's "bad" to use RPC, but imho it's sometimes the cleanest/simplest interface you can make for something on an API.

There's nothing wrong with RPC APIs. Other than being "Not Cool" due to the legacy of SOAP, they can deliver some very nice value.

Various RPC mechanisms like Bond and Protocol Buffers (and more recently GRPC) are trying hard to make RPC cool again. Personally, I hope they succeed, as REST (like any technology) doesn't work for everything.

Re: Microsoft REST API Guidelines

#122

Earlier quoted context omitted.

Delta queries are pretty easy, assuming you have a rich data store behind your data. As others have said, your data store needs to be able to say, "Show me changes since XYZ". Most of the Big Apps can do that, and from there the problems is one of API Semantics. This doc addresses the API Semantics, rather than the application design. To try to solve the design problem would be impossible as every application is diff…

I understand what the doc is trying to convey, I just hadn't ever thought of the application-level logic for record deltas before, so I got incredibly distracted from the document. It made me wonder how other people, not using temporal tables, are accomplishing this right now.

I don't think I've ever seen delta's done at-scale with actual temporal tables, but rather with transaction Id's of some sort.

For example (based on the doc) when you register a delta link, there's a row written to Azure Tables saying, "owner:iheart2code, deltaToken:foo, lastRecordIdSeen:123".

When you then make the Delta request, we look up "foo" for you, find that the last id you've seen is 123, and then only give you records from the transaction table with an id larger than that.

Temporal is always a can of worms, as clocks are impossible to keep in sync and there are endless race conditions.

Making the delta tokens causal, rather than temporal, is the way to go. Anything else is brutal in the distributed systems world...

Re: Microsoft REST API Guidelines

#123

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?

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, this wouldn't work.

Other services, such as XBox, and (very old) Azure, put the API version in a custom header (x-ms-version, for example). This proved to be extremely problematic, and every team that does this had stories of all the problems it caused and then spends time removing it.

I've never seen a detailed proposal for putting API version in the Content-Type header, and will go look.

The content-type header does seem to have many of the same drawbacks as putting the version in a header (any header). For example, people could not make queries from a browser just by entering a URL as there is no way to specify a header. Nor could someone bookmark an API GET request, which is also quite handy.

Ease of use is huge, and I am in the camp that a version in the URL (path or parameter) is much easier in every way than a header. Every with curl, it's easier (I can never remember how to specify headers w/o the man page).

Re: Microsoft REST API Guidelines

#124
post #75

Pagination is one of those things I feel like so many of these things get wrong. LIMIT/OFFSET (or as MS likes to call it, TOP/SEEK) style results in O(n²) operations; an automated tool trying to pull the entirety of a large collection in such a scenario is not good. I have to again recommend the excellent "Pagination done the Right Way" presentation[1] from Use the Index, Luke (an equally excellent site). Just return…

Returning just an array from a json-endpoint that may contain sensitive data is a vulnerability: http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-js... (edit: may be mitigated in newer browsers)

There is no maybe for newer browsers. The site linked says it is safe for Firefox >2 , IE ≥ 6 and all of chrome.

Re: Microsoft REST API Guidelines

#125
post #10

Earlier quoted context omitted.

Agreed, and specifically: > APIs will continue to be a disparate system that requires custom code for every integration until we can embrace the full benefits of REST Have an example of a client that DOESN'T require custom code to use an API? I think this entire debate is summed up best by: > There is no magical "smart client" that somehow knows that rel=comments means that the link leads to comments about the curren…

No clients know that "comments" means Comments, because no one has standardised it yet. There's no reason that we can't define "rel=comments" as being the comments for something, in the same way that https://schema.org/ has defined schemas for a range of taxonomies on the web already. I don't have an example of a public API that can be used by a generic client because no one is making them. I've played around with th…

> No clients know that "comments" means Comments, because no one has standardised it yet.

Given that 'Comments' on HN are different than comments on Facebook, comments on a sales invoice, comments in a threaded forum, and comments on a pull request, how will this get standardized? On their face they may have relatively similar goals, but they have different semantics, rules and ways of being displayed.

On top of that, what happens when I create a new application, with a new object concept that's not standardized? Do I have to wait for it to get standardized and implemented in this magic client before I can launch? Or do I have to build a custom client anyway, entirely negating the point of using standardized stuff in the first place?

It's conceivable that with enough effort, some client could understand the semantics of all object types that are contained in a standard, and the standard is big enough to cover ever situation ever possible.. But then what? Who wants to build an app that basically looks and functions identically to your competitors (who are all using the same semantic objects)?

Re: Microsoft REST API Guidelines

#126
post #10

Earlier quoted context omitted.

Agreed, and specifically: > APIs will continue to be a disparate system that requires custom code for every integration until we can embrace the full benefits of REST Have an example of a client that DOESN'T require custom code to use an API? I think this entire debate is summed up best by: > There is no magical "smart client" that somehow knows that rel=comments means that the link leads to comments about the curren…

The thing is, those servers and clients already exist, people are just to tied to their notion of "API" to see them. And in fact, you used them to post that very comment. A website is a RESTful service which a generic client can interact with despite not having any custom code. Does it do so by magically understanding what an or tags are or by magically decoding PNG bytestreams? No, the service uses standard formats…

> No, the service uses standard formats that the browser knows and which encode these semantics, allowing it to process them despite its original developers quite possibly not even knowing that service existed.

You're correct.

But that's not what we're talking about. We're talking about a web browser that can understand its posting a Comment, not a form (or a random collection of key-value pairs). The primitives that make the web work are quite different from the high-level concepts that make an application work.

My browser understands how to display links and forms and text and graphics. It does not understand how to display a comment or a user account or the number of votes a comment has, let alone know when I'm allowed to vote up or down, understand the relationship between a user account and a comment, understand a comment being owned by my user account or another, etc, etc.

What exactly is the end goal? That a HATEOAS-style REST API can be created, you can go to some entry point with your browser, and with no one writing any UI code it just understands how to render the Hacker News site? It will magically understand that the main page contains a list of articles, those articles have comments, links to an original source, etc?

This is my understanding of the goal of HATEOAS. If that's not the goal, I don't understand what it gets besides being a way to build a tiny part of documentation necessary to consume an API.

Re: Microsoft REST API Guidelines

#127
post #118

Earlier quoted context omitted.

No $filter is a horrible construct which accepts a free-form expression that doesn't map cleanly to any variable that's effectively being used as a tunnel to pass an opaque query blob from OData client to an OData server resulting in an anti-pattern violating Microsoft's own Service design guidelines: https://msdn.microsoft.com/en-us/library/ms954638.aspx?f=255... $filter is an unnatural implementation detail leaking…

There are a number of examples to cite showing what you say isn't true. Allowing totally arbitrary OData $filter expressions does lead to problems, but recent versions of OData have a nice mechanism to describe (and discover) what can be filtered on. This is both tooling and developer (for consumption) friendly. There are many examples of teams providing OData API heads without using SQL as the data store. Teams do t…

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 exposed `?productName=cupcakes` you'd have no such implementation coupling.

Now you're saying you can combat this with recent versions of OData that have filter metadata which is a problem in of itself, additional features, additional metadata services, additional training, additional complexity, etc - making OData an endless rolling spec where eventually every OData client except those developed by Microsoft will fall off the upgrade cliff and no longer see ROI chasing an endless spec. OData's just another big, heavy, tooling-dependent, slow and over-architected, complicated framework - you can avoid it's manufactured problems and create cleaner, faster, more interoperable, more human-friendly and future proofed API's by simply avoiding it in the first place.

Re: Microsoft REST API Guidelines

#128
post #81
post #53

Earlier quoted context omitted.

This isn't just some poorly labelled content from a 10 year old legacy website from a time before they knew any better, the OData website got a recent redesign sporting new Stock photos and even larger font for their disingenuous labeling which still continue to push OData crapware under the REST banner to fool devs/CIO's into thinking if they adopt OData they're taking advantage of the best form of REST - which is i…

I recently had the misfortune to have to tackle oData to talk to Dynamics CRM. The choice was between that and SOAP so it was the lesser of two evils. But compared to the other nice, modern REST API's I'm used it smelt of mould and enterprisey cobwebs. I'd have preferred an old school RPC API over that. At least API's that abuse REST from that direction tend to have the virtue of simplicity.

Sure, but is the smell because of OData or is that smell mostly coming from the messy old enterprise cruft that an OData veneer has been applied over? I can't really speak to how Dynamics did this in detail, but on my crusty enterprise platform with a huge existing api surface we did a veneering project as a rest v1 using OData (intentionally avoiding esoteric bits, but using query, $metadata, and limited relationships). It does have an enterprisy cobweb feel in places but I think that'd be present if we'd done it without OData as well.

Re: Microsoft REST API Guidelines

#130
post #127

Earlier quoted context omitted.

There are a number of examples to cite showing what you say isn't true. Allowing totally arbitrary OData $filter expressions does lead to problems, but recent versions of OData have a nice mechanism to describe (and discover) what can be filtered on. This is both tooling and developer (for consumption) friendly. There are many examples of teams providing OData API heads without using SQL as the data store. Teams do t…

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 with a custom solution - until you then want someone other than your clients to pull data from. Then they need to build their filter in your language, which is of course different than the next guy's language, and so on and so on.

The fix for this is OData. Not all of OData - just a little bit. It lets one standardize the filter expression syntax (as much of it as you choose to support) without making any requirements on the backend.

I'm personally confident in making the claim that OData $filter doesn't require you to bind to a server implementation, because I work on a service built in Node.js and deployed on Linux in Azure that uses OData as a filter syntax and satisfies it's data requirements from three completely different backend servers, none of which is a SQL Server (not that you mentioned SQL, but it's often cited as "all that OData is good for"). One of them is Elastic Search, BTW :), the other is a proprietary aggregated metrics store, and the third is a cloud-scale columnar data store. All three of these can be queried with the same syntax, from tons of off-the-shelf OData consumers, and for clients the choice of what backend to pull data from is literally the only thing they change. From a business value perspective this is pure win, and this is due in large part to using just a little OData, at just the right spots.

I think of OData like salt in a recipe - a little bit is great; too much ruins the dish. Moderation in all things... :)

Post reply on HN