Executing a request again results in 412 Precondition Failed


#1

Im experimenting with the Github GraphQL API and Apollo on iOS. The first time I execute a request, it succeeds, but the second time results in a 412 Precondition Failed. The workaround is to add/remove an additional field from the request each time I run it.

response headers:
{ status code: 412, headers {
“Access-Control-Allow-Origin” = “*”;
“Access-Control-Expose-Headers” = “ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval”;
“Cache-Control” = “private, max-age=60, s-maxage=60”;
“Content-Length” = 0;
“Content-Security-Policy” = “default-src ‘none’”;
“Content-Type” = “text/html;charset=utf-8”;
Date = “Mon, 06 Mar 2017 14:05:52 GMT”;
Etag = ““4cfc466d57a857ac4ae3facb032b034b””;
Server = “GitHub.com”;
Status = “412 Precondition Failed”;
“Strict-Transport-Security” = “max-age=31536000; includeSubdomains; preload”;
Vary = “Accept, Authorization, Cookie, X-GitHub-OTP”;
“X-Content-Type-Options” = nosniff;
“X-Frame-Options” = deny;
“X-GitHub-Request-Id” = “D6FD:32C0:1F84286:281EA45:58BD6CC0”;
“X-RateLimit-Limit” = 200;
“X-RateLimit-Remaining” = 190;
“X-RateLimit-Reset” = 1488812570;
“X-XSS-Protection” = “1; mode=block”;
}


#2

Could you please provide the query you’re using?


#3
query PublicRepos {
viewer {
    login
    repositories(first: 10, privacy: PUBLIC) {
        edges {
            node {
                name
                projects(first: 100) {
                    edges {
                        node {
                            name
                        }
                    }
                }
            }
        }
    }
}

}

Interestingly, if I disable caching from the Apollo client, it works. But surely, the 412 is coming from Github? Ill create an issue with Apollo


#4

Any news from Apollo? I was unable to reproduce a 412 while running this.


#5

I pinged them on Slack, and created an Issue:
https://github.com/apollographql/apollo-ios/issues/70


#6

@gjtorikian: Hi, I’m Martijn, the author of Apollo iOS.

If I understand the meaning of 412 Precondition Failed correctly, this happens because we’re making a POST request and the ETag no longer matches the one returned for the same resource before. I have no idea what this would mean in the context of a GraphQL API however, because there is only a single endpoint and that seems to make ETags rather useless.

Do you know what the ETag returned by the GitHub API is based on? Should clients pay attention to these at all?

It seems this may simply be an incompatibility between the default iOS caching strategy and the way the GitHub API has been set up, so disabling caching on the client may be the best solution. I’d still like to understand what is going on however.


#7

Yes, it’s based on the Vary headers, plus the response body. I wonder if repositories or projects is missing a sort somewhere, such that the response is different on subsequent requests?


#8

Hmmm, but even without a missing sort, couldn’t the response be different simply because repositories or projects have been added?

More fundamentally, it seems to me conditional requests with ETags break down in GraphQL because all requests can (are often are) sent as POST. How could ETags function if the request URL is always the same and the operations are in the POST body?

Also, unlike requests that follow HTTP semantics, where GET requests are idempotent and POST requests are not, there is no way to differentiate queries from mutations at the HTTP level. That means the difference between a 304 response (for a conditional GET) and a 412 response (for a conditional POST) is pretty meaningless and should probably be avoided.


#9

@gjtorikian: Just wanted to bump this to discuss how we can best fix this (either on our or on your side).


#10

No worries, I think it’s going to end up being a fix on our side. We were talking about just disabling ETags for GraphQL POST requests, basically.


#11

Good to hear, that makes sense to me.