Page MenuHomePhabricator

Set up an API base path for REST and action APIs
Closed, ResolvedPublic

Description

Using as few domain names as possible improves performance by:

  • Reducing the number of DNS names to resolve
  • Reducing the number of TCP (slow start) and TLS connections to set up, especially with SPYD/HTTP2

Currently https://rest.wikimedia.org/ is used to load HTML content in VisualEditor. As discussed in T94784, measurements show that about half of the load time on cold start (first access to rest.wikimedia.org) could be eliminated if the API was using the same domain & connection:

pasted_file (394×693 px, 43 KB)

Technically setting up such an entry point should not be too hard in Varnish. The difficulty is in finding the right name. Candidates:

  • /api/ prefix, with /api/v1/ and /api/action/ children
    • can provide a listing of available apis at /api/
    • a single API prefix is easy to match in Varnish configs, and can be used as a single config target for API clients that consume several APIs
    • the action api could make the action itself a path component: /api/action/query?prop=revisions&..
  • /api/rest/v1 instead of /api/v1/ - don't use the magic 'v1' name
  • alternative prefixes like /_api/, /:api/ or /_/ - won't conflict with articles at /{title} even if we removed /wiki/ (see https://www.mediawiki.org/wiki/Requests_for_comment/Clean_up_URLs)
  • use the root directly: /rest/v1/ or just /v1/

Current discussion status

We discussed this over the last days & this morning on IRC. Summary:

  • There is broad support for the /api/{name}/ pattern.
  • We want to keep our Varnish setup simple by mapping each API to a single backend.
  • The concrete names for the REST and action APIs are not 100% decided yet, but
    • @Anomie was supportive of using /api/action/ as a prefix for the action API
    • Several participants (@chasemp, @mobrovac, @BBlack) supported the /api/v1/ prefix for the REST API; @ori signalled his support as well, but proposed that we could wait a bit before doing so.

Next steps

We have two main options:

  1. Decide to move forward with /api/v1/
  2. Move forward with a temporary / uncontroversial name like /api/x1/, use that for VE only in private, then decide on the longer term name a bit later.

See also:

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
GWicke renamed this task from Create a path entry point for the REST API under regular domains to Set up a generic API base path to be used by action & REST APIs.Apr 8 2015, 5:14 PM
GWicke added a subscriber: Anomie.

The other security aspect is XSS, although this is not new as the HTML content has already been loaded from the actual domains for a couple of years now. In newer browsers, CSP headers also help to avoid many of those issues altogether.

Also, RESTbase already sends liberal CORS headers with its responses anyway.

GWicke raised the priority of this task from Medium to High.Apr 9 2015, 12:47 AM
GWicke added a project: VisualEditor.

I think we just observed the fairly dramatic impact of using a separate domain on cold load latencies:

pasted_file (1×1 px, 174 KB)

At ~14:10 PDT enwiki was switched to load HTML directly from RESTBase. Client-observed HTML load times looked good, roughly half the latency of the PHP API load. At around 16:30 we then switched over all wikis, and mean and 99% load times got a lot worse, worse in fact than those from the PHP API.

We have checked the metric definitions in VE, and it looks like these numbers are legit. We rolled back the all-wiki config change as a result.

Current theory is:

  • enwiki VE users have fairly low-latency internet connections, while all wikis have not
  • most VE users use TLS
  • on high-latency connections, setting up a brand new TLS connection to a relatively obscure host name takes on the order of 1.5s, which is responsible for the increase in latency we saw

Given the measurement data above from a low-latency connection (cable in SF) this seems plausible. We saw about 210ms connection setup with a round-trip time to the DC of ~80ms. With a DNS cache miss this would easily become 350ms. At 250ms latency and limited bandwidth this quickly adds up to > 1s just for the connection setup, followed by a slow-start phase that's again extended by latency.

I think this illustrates pretty well why we should minimize the number of domains we use, especially for users with high-latency internet connections.

GWicke renamed this task from Set up a generic API base path to be used by action & REST APIs to Set up an API base path for REST and action APIs.Apr 9 2015, 3:21 AM
GWicke updated the task description. (Show Details)
  • on high-latency connections, setting up a brand new TLS connection to a relatively obscure host name takes on the order of 1.5s, which is responsible for the increase in latency we saw

How sure are you about this? While a performance impact sounds plausible, 1.5s feels like too much. NavTiming should have the data to back this up or refute it (the data should be in EL).

As for the rest, the current usecase sounds fine to me but given RESTBase's current plan of becoming a proxy for all those different services (written by different teams and varying expertise), it sounds a little bit scary to trust it with cookies (& the capability for XSS as you rightfully point). Does this mean that each and every service would need to have a thorough security review now?

Security & privilege separation was a big selling point for SOA and I think it's time to deliver this — let's not do this on a whim. I'd like to at least hear from @csteipp about this...

How sure are you about this? While a performance impact sounds plausible, 1.5s feels like too much. NavTiming should have the data to back this up or refute it (the data should be in EL).

Yeah, I'm also sceptical that it explains all of the difference, but am confident that it explains the vast majority of it, especially considering the difference between enwiki and other wikis. Do you have a pointer to relevant metrics?

As for the rest, the current usecase sounds fine to me but given RESTBase's current plan of becoming a proxy for all those different services (written by different teams and varying expertise), it sounds a little bit scary to trust it with cookies (& the capability for XSS as you rightfully point).

If we worry about raw cookies being abused by services, then we could exchange those cookies against other tokens in RB before passing those on to the backend services (along the lines of the SOA auth RFC). Both cookie and token schemes are better than granting services full rights to do whatever they want to do independent of the request. All of our PHP code not only has full access to cookies, but also full database access, which includes user password hashes and other sensitive information. The risk of confused deputy issues is a lot higher if any part of the system can easily escalate privileges.

As for the client side: Our cookies are HTTPOnly, and we set the right headers to disable XSS in anything but really old browsers. I also don't see a reason why services emitting HTML should be held to lower standards wrt XSS sanitization etc than other ways of generating the same content.

Does this mean that each and every service would need to have a thorough security review now?

Yes, that was and still is the case. For example, Parsoid output has been used in authenticated contexts for a few years now, and we won't magically be able to stop sanitizing our content just because we are now serving it with services.

As for the client side: Our cookies are HTTPOnly, and we set the right headers to disable XSS in anything but really old browsers. I also don't see a reason why services emitting HTML should be held to lower standards wrt XSS sanitization etc than other ways of generating the same content.

My argument against this is that,

  1. There is a direct correlation between features and lines of code, and flaws that will be found. That's why "Simplicity" is a security principle, and why any hardening standards you look at will emphasize the importance of turning off unused features. So even if we're holding these services to the same standard we currently use for code, putting them on the same domain *will* increase the number of vulnerabilities in our site.
  1. Cookies being set HTTPOnly is good hardening, but there have historically been attacks to get around it (remember Cross-Site Tracing [https://www.owasp.org/index.php/Cross_Site_Tracing] and http://seckb.yehg.net/2012/06/xss-gaining-access-to-httponly-cookie.html ?).

Segmenting to different domains will give us another layer of security [https://www.owasp.org/index.php/Defense_in_depth] for when things go wrong. So I really don't want us to take this decision lightly.

When we talked about running restbase on the same domain as the wiki, that let us simplify the authentication handling, yay! But if restbase is going to proxy other services too (which we hadn't discussed at the time we were talking about this), then we need to reevaluate that decision, and see if it's worth the security trade-off. The more services restbase proxies, the more we should consider putting it on a separate domain and using a different authentication scheme.

@csteipp: I think that a big rethink of how we do authentication in general in order to protect old browsers is big enough to deserve its own RFC. For example, since most content in regular page views is user-provided, we could stop setting authentication cookies on the main project domain for projects that don't require it for reads. We could then have a separate domain that only specializes on the small minority of authenticated requests. At the minimum, this would slightly improve protection for old browsers that don't support CSP and related headers, which to my knowledge account for a small single-digit percentage of requests.

In the meantime, this patch does not change the status quo of content being primarily served from the main project domain. It leaves the door open for a rethink as describe above, but also lets us move forward with important performance improvements in our top priority project.

In the meantime, this patch does not change the status quo of content being primarily served from the main project domain. It leaves the door open for a rethink as describe above, but also lets us move forward with important performance improvements in our top priority project.

It does change the status quo. Graphoid is 530 kloc's of javascript. I've looked at the pieces Yuri wrote, and it generally looks sane. I don't think you or Yuri have looked through all 500k other lines of code to make sure there are no vulnerabilities. If you have, that's awesome. It would take me about 3 months to audit that line-by-line. When we include new PHP libraries on our main domain, I do audit that code line-by-line.

My concern with just pushing this out is that more and more code will then rely on the services being on the main domain, so extracting them 3-6 months from now will be more work than anyone is willing to do.

If we need restbase on the primary domain for VE performance, can we put it there without proxying other services? I would be ok with that.

> If we need restbase on the primary domain for VE performance, can we put it there without proxying other services? I would be ok with that.

Just 2 cents on my part:

I am not sold at all at the idea of proxying via RESTBase any service. It is a very young software (<2 months of production use) with a not yet proven record in either stability or security, a state which, depending on the adoption rate by third-parties (assuming of course something like that ever happens) as well as internally, might stay that way for a long time. Apart from all the security issues @csteipp points out, there is also the issue of availability. Simply put, if we put X services behind RESTBase and RESTBase fails, X services will fail as well (in varying degrees and depending on how we set up layers above RESTBase like Varnish). No matter how we set up defences against that scenario, they will add complexity that will need to be understood and managed. I dislike complexity.

I personally would feel a lot better if RESTBase instead of a proxying/caching layer, it's role as a cache was fulfilled in a more memcached like scenario where services would look up content in RESTBase and failing to find it, would generate it and store it in RESTBase for subsequent users/uses.

Graphoid is 530 kloc's of javascript.

If the codebase is too large to review, then why don't we focus on sanitizing the output? It produces SVG and PNG. Our main concern is probably SVG. We know how to sanitize SVGs, and should probably just apply those transformations to all SVG output in RESTBase. Also, only IE8 seems to support SVG, but not CSP. However, IE8 does support X-XSS-Protection, so there's a chance that it might not execute JS in SVG either, even if our sanitization failed.

My concern with just pushing this out is that more and more code will then rely on the services being on the main domain, so extracting them 3-6 months from now will be more work than anyone is willing to do.

I think extracting non-authenticated content is the wrong approach if you want defense in depth. Most of our content is user-provided and could be incompletely sanitized. If you want to use domains to protect old browsers, then you probably want to extract actions that really need authentication & stop setting cookies on the main domain, rather than doing it the other way around.

If we need restbase on the primary domain for VE performance, can we put it there without proxying other services? I would be ok with that.

It is obviously technically possible, but would be messy. We'd have to document which end points are available at /api/v1/, and which aren't.

then you probably want to extract actions that really need authentication & stop setting cookies on the main domain, rather than doing it the other way around.

Didn't we get rid of secure.wikimedia.org in part because having two different ways of accessing the same content confused users all over the place? Having one domain for logged-in users and one for anons sounds like the same sort of problem.

@akosiaris: Regarding RB as SPOF: We have that risk wherever we unify the URL space, be that Varnish or RB. Your likely preferred solution of separate domains for each service has negative implications for performance, authentication support and discoverability. We can and will use standard techniques to manage the availability issue, like separate RB clusters for different groups of applications, canary and rolling deploys etc. As you know, RB itself is symmetrical and designed without SPOFs. In any case, this argument is orthogonal to whether RB is exposed at rest.wikimedia.org or elsewhere.

@akosiaris: Regarding RB as SPOF: We have that risk wherever we unify the URL space, be that Varnish or RB.

Yes, but there is a difference in how proven Varnish (or squid for that matter) is in the battlefield and how much RB.

Your likely preferred solution of separate domains for each service has negative implications for performance, authentication support and discoverability.

Performance ? Yes, a few ms are definitely added in every request.
Authentication support ? Mind expanding a bit ? Preferably not on this ticket (an orthogonal discussion as you already pointed out)
Discoverability ? Isn't that a joint goal of both services and ops ?

We can and will use standard techniques to manage the availability issue, like separate RB clusters for different groups of applications, canary and rolling deploys etc. As you know, RB itself is symmetrical and designed without SPOFs.

Managing the availability issue, as we have already extensively discussed that both ops and services will jointly do is one thing. Avoiding its implication on multiple services is another one entirely.

In any case, this argument is orthogonal to whether RB is exposed at rest.wikimedia.org or elsewhere.

That is true.

Your likely preferred solution of separate domains for each service has negative implications for performance, authentication support and discoverability.

Performance ? Yes, a few ms are definitely added in every request.

Our data above shows a lot more than a few ms impact on the first request to a domain.

Authentication support ? Mind expanding a bit ? Preferably not on this ticket (an orthogonal discussion as you already pointed out)

A difference is whether cookie-based authentication can be used or not.

Discoverability ? Isn't that a joint goal of both services and ops ?

I mean this as in API documentation. Random subdomains are hard to guess if there is no listing.

Graphoid is 530 kloc's of javascript.

If the codebase is too large to review, then why don't we focus on sanitizing the output? It produces SVG and PNG. Our main concern is probably SVG. We know how to sanitize SVGs, and should probably just apply those transformations to all SVG output in RESTBase. Also, only IE8 seems to support SVG, but not CSP. However, IE8 does support X-XSS-Protection, so there's a chance that it might not execute JS in SVG either, even if our sanitization failed.

@GWicke, I have to pick on this for a minute-- this is exactly the reason I'm pushing for more defense in depth and isolation between services. If Yuri hadn't had a security review of the graph extension already, where we found that Vega was executing JavaScript from the graph definition, and we just blindly included it (like were doing for about 500klocs of libraries right now), it would be arbitrary code execution on the graphoid server.

So we can't only focus on one attack vector. We need layers of security even when we think we've mitigated for every attack we can think of. Domain isolation, network isolation of the servers, mandatory access controls on the process-- they're all layers in case we miss something, to make an attackers life harder and give us some chance of detecting when one succeeds.

@csteipp, afaik nobody suggests that we should focus on one vector only. Additional output sanitization can add one layer of security, and help to reduce the risk to a point where we can expose it on an authenticated domain.

@GWicke and I talked in person and agreed that if all service output that is html, svg, or any other xml-derived format is run through an extra sanitization filter that services and security teams will manage together, and assuming the most restrictive html headers we can set for the functionally are being set, then I'm ok with restbase proxying those services on our primary domain, from a security perspective. I think we can roughly offset the loss of security that we incur by moving to a single domain by having an extra, standardized filtering layer for all the services there (it's basically running a custom WAF in front of all our services).

Ops still needs to be comfortable with that strategy, but I'll let you guys figure that part out.

Ops, from my perspective, it would be really great to be able to plan for using alternate, unauthenticated domains in the future, so it would be really helpful to get the performance issues figure out (serve them from POPs, optimized for spyd, etc), regardless if restbase is served from one now, or not.

Ops, from my perspective, it would be really great to be able to plan for using alternate, unauthenticated domains in the future, so it would be really helpful to get the performance issues figure out (serve them from POPs, optimized for spyd, etc), regardless if restbase is served from one now, or not.

Basically in order for the user experience for SPDY and such to be optimal, everything the user hits need to (a) resolve to one IP and (b) match the same certificate. However, we also can't make the certificates huge and include all (currently 25 and I'm sure growing) domains in every cert - we just recently refactored our certs in the other direction actually. Lots of hostnames is actually ok, it's the lots of domainnames that isn't - so it's important to be explicit about the difference between a hostname and a domainname here.

What we're already possibly-planning around is including *.wikimedia.org in all of the certs so that potentially one IP + one cert can handle all of a user's traffic for e.g. *.wikimedia.org + *.wikipedia.org (or *.wikimedia.org + *.wikiversity.org). This would allow for deploying N future services as $foo.wikimedia.org and all of them sharing SPDY coalescing with the user's primary connection to e.g. en.wikipedia.org. But this whole idea does not extend to multiple domains, as if we tried to do it with en.wikipedia.org + wmfrestbase.org + wmfservice2.org + wmfservice3.org, etc. That doesn't scale for connection coalescing.

What we're already possibly-planning around is including *.wikimedia.org in all of the certs so that potentially one IP + one cert can handle all of a user's traffic for e.g. *.wikimedia.org + *.wikipedia.org (or *.wikimedia.org + *.wikiversity.org). This would allow for deploying N future services as $foo.wikimedia.org and all of them sharing SPDY coalescing with the user's primary connection to e.g. en.wikipedia.org. But this whole idea does not extend to multiple domains, as if we tried to do it with en.wikipedia.org + wmfrestbase.org + wmfservice2.org + wmfservice3.org, etc. That doesn't scale for connection coalescing.

Yep, being able to setup a new $foo.wikimedia.org domain, and not get penalized in performance when using spdy is what I was looking for. Even if restbase doesn't use it, it's a good tool to have in case we want to bring something more risky in or segment something like search out.

If we have a service that would use it, is there an estimate on how long that would take to get setup the first time we want it?

It would be great to use this for upload (and bits) especially. DNS lookups have a cost too, so we'll probably want to keep the number of domains limited in any case.

Since the comments on the gerrit change seem to not be having any real attention paid: I (and apparently also @MaxSem) think that "/api/v1/" for restbase is likely to be needlessly confusing when it's not the only API available. "/api/rest/v1" would be clearer, if you don't want to use the full "restbase" name in there.

@Anomie, my understanding is that there are no plans to version the action api, which is why I believe /api/action/ could work well. We'll have two APIs no matter what, and a future v2 or v3 API would just add to that. I think a subdirectory for the rest API(s) would mainly help if there are other APIs that follow the same versioning scheme. I am not aware of any plans for that, and also believe that it would not be in the interest of our users to needlessly create a whole family of APIs rather than thinking about how we can integrate functionality in a consistent API. Listing all APIs at one level makes it easy to get a full list of APIs right away, and lets us present documentation for each api at /api/{name}/.

and lets us present documentation for each api at /api/{name}/.

You changed the name of restbase to "v1" now?

You changed the name of restbase to "v1" now?

No, 'v1' is the name of the API. RESTBase is the framework / proxy service we use to implement that API, but the same API could be implemented using FooBar as well.

Yep, being able to setup a new $foo.wikimedia.org domain, and not get penalized in performance when using spdy is what I was looking for. Even if restbase doesn't use it, it's a good tool to have in case we want to bring something more risky in or segment something like search out.

If we have a service that would use it, is there an estimate on how long that would take to get setup the first time we want it?

Probably best discussed over here: https://phabricator.wikimedia.org/T94896 , but really we haven't made any decisions on this stuff yet, and there's definitely real blockers on refactoring nginx config and getting all certs reissued for $$$ from GlobalSign.

@Anomie, @MaxSem: Does the /api/{name}/ pattern work for you?

The /api/{name}/ pattern seems ok, although I still find "v1" to be a strange name for restbase.

The /api/{name}/ pattern seems ok, although I still find "v1" to be a strange name for restbase.

I don't see v1 as the name for RESTBase, but rather as the version of the content API. In that context, en.wp.org/api/v1/page/html/Foobar makes more sense than en.wp.org/api/rest/v1/page/html/Foobar (to me at least). API consumers shouldn't really care if it's RESTBase, PHP or something else producing the information, what matters is the contract between the endpoint and its users.

I don't see v1 as the name for RESTBase, but rather as the version of the content API.

Above Gabriel claimed "v1" was the name. If it's the version then it's not following the /api/{name}/ convention, is it?

Where are we going to place non-restbase services in this URL path schema relative to restbase? I assume "page" isn't the name of restbase either. If the intent is that all future services are part of the restbase scheme and live underneath the paths at /api/vN/ (and route to the restbase service cluster from e.g. varnish, before possibly going elsewhere), let's be explicit about that.

But if, as I really expect, we're going to continue to deploy new services that do not route through the restbase codebase/cluster, it would be nice to have a sane URL path scheme that differentiates them within /api/ (or /:api/, or whatever). API *consumers* may not care whether a given path under /api/v1/ happens to be RESTBase or PHP, but our request-routing of URLs to service clusters definitely does care that there's a sane, differentiable scheme there.

Above Gabriel claimed "v1" was the name. If it's the version then it's not following the /api/{name}/ convention, is it?

Yes, v1 is the name. To rephrase my earlier comment, you shouldn't think of v1 as the name of RESTBase, but the name of the content API.

Where are we going to place non-restbase services in this URL path schema relative to restbase? I assume "page" isn't the name of restbase either.

If under RESTBase, each content type or service gets its own sub-hierarchy. In the above example, /{domain}/v1/page/html/Foobar, page is just the name of the module serving content in that hierarchy, i.e. html/Foobar.

If the intent is that all future services are part of the restbase scheme and live underneath the paths at /api/vN/ (and route to the restbase service cluster from e.g. varnish, before possibly going elsewhere), let's be explicit about that.

Opened T96688 so we can properly discuss this.

After a heated IRC discussion, there is consensus around the fact that there should be a 1:1 mapping between name in /api/{name} and back-end services.

Whether or not /api/v1 is acceptable for RESTBase is still under discussion. The main stepping stone is the fact that if v1 signifies version 1, then future APIs (not services!) might not have the same structure as RB-backed API. There currently seem to be three suggestions:

  1. /api/content/ maps to http://rest.wikimedia.org/{domain}/
  2. /api/v1/ maps to http://rest.wikimedia.org/{domain}/v1/
  3. /api/insert-your-random-name-1/ maps to http://rest.wikimedia.org/{domain}/v1/

My votes go (in order of preference) to (2) and (1).

After a heated IRC discussion,

I actually think it was a good example for a constructive discussion, despite having a lot of bikeshedding potential.

there is consensus around the fact that there should be a 1:1 mapping between name in /api/{name} and back-end services.

We basically all want to keep the Varnish config simple. A good way to achieve that for APIs is to map each API to a single Varnish backend.

Regarding naming, I think we should stick with one name per API, and not group multiple APIs under a single API name. My naming preference for the v1 REST API is /api/v1/ as well.

Also, RESTbase already sends liberal CORS headers with its responses anyway.

Another reason to do this, not yet mentioned as far as I see, is that CORS sometimes is broken. See also T64469.

I know @Tgr or @Gilles gathered some statistics on the level of 'brokenness' of CORS throughout the user base.

I know @Tgr or @Gilles gathered some statistics on the level of 'brokenness' of CORS throughout the user base.

That's T507, still ongoing.

Above Gabriel claimed "v1" was the name. If it's the version then it's not following the /api/{name}/ convention, is it?

Yes, v1 is the name. To rephrase my earlier comment, you shouldn't think of v1 as the name of RESTBase, but the name of the content API.

It seems to me that quite a few people (myself including) have already more than once thought of v1 as a version string and not a name. I can only assume more people will fall into that trap.

Whether or not /api/v1 is acceptable for RESTBase is still under discussion. The main stepping stone is the fact that if v1 signifies version 1, then future APIs (not services!) might not have the same structure as RB-backed API. There currently seem to be three suggestions:

I assume RESTBase here just slipped here by as one implementation service of the API. So s/RESTBase/API/

  1. /api/content/ maps to http://rest.wikimedia.org/{domain}/
  2. /api/v1/ maps to http://rest.wikimedia.org/{domain}/v1/
  3. /api/insert-your-random-name-1/ maps to http://rest.wikimedia.org/{domain}/v1/

I dislike 2., as I already said because it clearly signifies a version to me (and to other people as well as it seems). If we go with it, I can only suppose it will confuse a lot of other people in the future as well. Especially if another API - which does something completely different - does show up in the future, which is something not impossible to happen in 3, 5 or 10 years.

I dislike 3., what is the need for a 1 at the end ? It manages somehow to signify a version again and is not at all different from proposal 2.

1 is my choice here. I am backing that up with:

I don't see v1 as the name for RESTBase, but rather as the version of the content API.

Yes, v1 is the name. To rephrase my earlier comment, you shouldn't think of v1 as the name of RESTBase, but the name of the content API.

  1. It has already been called the content API at least twice in this discussion but somehow when the naming discussions starts it is not given the name at least some people actually call it with.
  2. The fact that this entire discussion seems to revolved around the content (the word content appears more that 20 times in pretty much the same context - serving it to users).
  3. The fact that there is a /action endpoint already proposed in this very same proposal for a completely different and unrelated API that is called the action API. Giving an API a name clearly denoting what it is/does is and the other one a name not clearly denoting what it is/does (at least at this point in time) is begging for confusion.
  4. The fact that we can always create a different endpoint should one of the APIs end up doing more than what it's - then current - name suggests. So if the content or the action APIs end up doing more that just content (or actions respectively) we can rename it anyway.
  5. Numbers (especially naturals ones) tend to give an expectancy of sequentiality, especially when appended to a string. Expecting something is generally a sure way to confusion when that is not fulfilled.

As a side note, I am fine with the content API being called the abracadabra API and having a /api/abracadabra/ endpoint now or in the future but please do refrain from an endpoint /api/abracadabra1/

I second @akosiaris sentiment - #1 (/api/content/v1/...) seems like a much cleaner choice out of the once mentioned above. Alternatively, unless there is a good reason not to, we could put the api into the domain, e.g. //api.wikimedia.org/content/v1/.... We could even call it //42.wikimedia.org/content/v1/... for everything (rfc1123 allows digits).

Alternatively, unless there is a good reason not to, we could put the api into the domain, e.g. //api.wikimedia.org/content/v1/...

Unless I'm mistaken, the motivation behind this proposal is because hitting /api/content/etc on the local domain avoids CORS issues and the need for the browser to setup a new TLS connection, which have been observed with hitting the existing rest.wikimedia.org domain.

Thanks @Anomie. So back to /api/content/v1/, or a shorter /a/c/1/ since some browsers might not support header compression, and it will be easy enough to document ))

Personally I'd much rather see the reasonably clear /api/content/ than the cryptic /a/c/.

The problem with 'content' is that it is not general enough, as this API will expose non-content information as well. Using v1 avoids the need to narrow down the type of content by only communicating the version, but is more suggestive of being *the* major API. Which I think we should strive for, but is not yet the case.

As a compromise, how about /api/rest_v1/? The 'rest' prefix distinguishes it sufficiently from 'action', and avoids the suggestion of it being the only versioned API around.

I'd still prefer something more descriptive than "rest"—as you said on IRC, it's the underlying technology rather than any indication of what it actually does—but "/api/rest_v1/" doesn't get a -1 from me.

The problem with 'content' is that it is not general enough, as this API will expose non-content information as well. Using v1 avoids the need to narrow down the type of content by only communicating the version, but is more suggestive of being *the* major API. Which I think we should strive for, but is not yet the case.

Why did you not say in the first place that there are aspirations that this could one day be *the* API? It could have shortened the length of this task considerably.

As a compromise, how about /api/rest_v1/? The 'rest' prefix distinguishes it sufficiently from 'action', and avoids the suggestion of it being the only versioned API around.

You do know what they say about compromises. No party ends up happy. Anyway I do see this as a very good step and I am fine if you want to go forward with it but I 'd like to counter propose something.

TL;DR: /api/_/v1/

What the above does is:

  • adhere to a /api/{name}/{version} scheme. /api/action adheres to that scheme as well, assuming {version} is optional.
  • It does not create a precedent where APIs have to leak/declare version info in their name.
  • Separate the API version from the API name, and clearly denote a hierarchical relationship between them.
  • Provide the content API with a name generic enough to allow the aspirations that it will become *the* API to flourish, without at the same time suggesting that it is the only versioned API around (a clear goal you just stated in /api/rest_v1/ and IIRC has been stated on IRC as well)
  • Satisfy @Yurik's shorter URL desire (well, OK, it's just 3 bytes shorter)
  • Not leaking implementation or supporting technology info.
  • Satisfy the technical requirement of a 1:1 mapping between URLs and Varnish Backends.
  • Provides flexibility for both current APIs as well as future ones as far as URL routing of versions goes. We have the ability to do version routing in Varnish or have Varnish delegate the version routing to a lower layer without too much VCL weirdness.

Do note that this violates Mark Masses' REST API Design Rulebook Rule that says underscores _ should be avoided in URIS and hyphens - should be used instead. My take on that is that in this specific case the _ is a name and not a separator in a URI resource so it is OK.

I am fine with exchanging the _ for whatever you feel like but I think it will be hard to find another so generic name for it.

Thoughts ?

TL;DR: /api/_/v1/

Eeew.

Thoughts ?

I have serious doubts about encouraging this idea that restbase (or whatever it's being called) is the be-all end-all of APIs.

How about mapping /api/foo/v1 to http://rest.wikimedia.org/{domain}/v1/foo (for some whitelist or non-blacklist)? Right now, RESTBase consists of a page content API prefixed with /page/ and a text transformation API prefixed with /transform/, and the fact that they are handled by the same system is an implementation detail that should not inform a stable, long-term naming schema.

Alternatively, the same schema could be used with the version number up front, if that's preferred - /api/v1/page for the page content API, /api/v1/transform for the text transformation API, /api/v1/action for the action API.

GWicke closed this task as Resolved.EditedApr 23 2015, 3:15 PM
GWicke claimed this task.

Sorry for now updating the ticket yesterday. We decided to go with /api/rest_v1/:

http://en.wikipedia.org/api/rest_v1/page/html/Compromise

This lets us move ahead with VE loading HTML from RESTBase without the performance issues around the separate domain & lack of geodns / local TLS termination. The nice thing about supporting multiple names in /api/{name}/ is that we can add new ones later.

@akosiaris, with the /api/{name}/{version}/ scheme I see the following issues:

  • Each API has to have a name, even if we end up with one main API at some point (can't move to /api/v2/ for that). The action API also does not have a version currently, and there is resistance against introducing it.
  • For clients, it is harder to list APIs, as it's necessary to recurse into each name sub-hierarchy. Each name/version combination is really its own incompatible API, otherwise there would be no need to increment the version. I think from this perspective it also makes sense to have a name like rest_v1.

@Tgr, moving the top-level hierarchies directly under /api/ would move part of the API structure into Varnish, complicating the config there (there will be more entry points). It would also be hard to consistently document the entire API when various entry points use different styles and auth schemes. We would end up with duplicate functionality, as a part of API evolution involves figuring out better layouts for existing functionality. With different APIs (v2, say) we can have a clean separation, where each API makes sense by itself.

I do share your emphasis on separating the API from the implementation. However, we can do this with /api/rest_v1/{something}/ as well. RESTBase is built around proxying requests to backend services, but we could just as well use any other proxy to do the same mapping without any API user noticing.

Change 206316 had a related patch set uploaded (by GWicke):
Use /api/rest_v1/ entry point for VE

https://gerrit.wikimedia.org/r/206316

Change 206319 had a related patch set uploaded (by GWicke):
Load HTML directly from RESTBase for enwiki

https://gerrit.wikimedia.org/r/206319

Change 206320 had a related patch set uploaded (by GWicke):
Load HTML directly from RESTBase on all wikipedias

https://gerrit.wikimedia.org/r/206320

Change 206316 merged by jenkins-bot:
Use /api/rest_v1/ entry point for VE

https://gerrit.wikimedia.org/r/206316

Change 206319 merged by jenkins-bot:
Load HTML directly from RESTBase for enwiki

https://gerrit.wikimedia.org/r/206319

Change 206320 merged by jenkins-bot:
Load HTML directly from RESTBase on all wikipedias

https://gerrit.wikimedia.org/r/206320