Hacker Newsnew | past | comments | ask | show | jobs | submit | dschafer's commentslogin

We've been using GraphQL at Facebook in production for almost five years now, and it powers a huge amount of our iOS/Android app's API traffic. We also did a comprehensive revisit of the core concepts when we open sourced it in 2015, and we heavily use tools like GraphiQL internally. I can definitely assure you that Facebook's support/usage of GraphQL isn't a fad.


Yeah, introducing a new field and deprecating the old one seems like the best option here. The nice thing is that while this introduces new functionality, there's still only one version of the server; if you query for `homePlanet`, you always get the name, if you query for `homePlanetDetails`, you always get the planet object. This is particularly useful for tooling, since the API response is a function only of the access token and the query.


FB's GraphQL APIs are only used by our first-party applications; for third-party APIs (where you don't control the callers), it definitely gets trickier for the reasons you note. One option would be to do some analysis of the query in advance (effectively, assign each field a "cost"), and reject queries that have too high of a cost. The "cost" metric could basically be "around how many objects will this return", so in the

  user {friends {friends {friends {friends{id}} } } }
case (which is the canonical example in FB's schema of a crazy query), we would note that there's a 5000 friend limit, and so that query would potentially query 5000^4 = 6.25e14 nodes, and based on that we would (hopefully) reject it.


This is a concern even for first-party apps, as you are not secure from a malevolant client. Or hell, your own client could have bugs which create some insanely expensive queries on, say, 1% of your devices - didn't catch it in QA, end up pushing it to millions of device for a nice ddos.


Surely you know that anyone can access the binary code of your first-party applications (using a jailbroken iPhone and a rooted Android device), decompile it (using jd-gui, the Hex-Rays ARM decompiler, etc.) and arbitrarily use the APIs they expose, right?


When building out a GraphQL schema, the schema developer chooses which functionality to expose to the client. So rather than having the client do operations or predicates directly, the server declares what functionality is available, and might expose functionality that ordinarily would have used operators or predicates.

For example, we might have the following query on Facebook's GraphQL schema:

  {
    user(id: 4) {
      followers(isViewerFriend: true, birthdaysInRange: {before: -2, after: 2} orderBy:NAME) {
        name
      }
    }
  }
EDIT: fix code formatting

Which fetches Zuck's followers, and filters it to only my friends, and only those friends whose birthdays are within two days of today, and then orders them by name.

The `isViewerFriend`, `birthdaysInRange` and `orderBy` parameters were explicitly added to the API by the API developer for clients to use.

So clients don't have the ability to do arbitrary operators, but we also know that the client is only using functionality in the API that the API developer chose explicitly to allow.


Any idea when this will work with Relay?


This is how Relay currently works


You can't presently pass other filtering arguments to a relay query. Just IDs.

Unless I am missing something, the above query wouldn't work in Relay.


You totally can. One restriction (that you might be confused with) is that Relay currently only supports root fields with a single argument (which would typically be an ID).

But arbitrary arguments on any other field are totally supported.


The GraphQL API acts as a layer atop application code; it assumes that the application code takes care of any access controls (since those access controls would apply to anyone querying that data, not just GraphQL). So there's nothing for access control built-in to GraphQL, but GraphQL can map to arbitrary access controls that exist in the application layer.

The GraphQL server can pass down authentication information through the query using `rootValue` (for example, it might pass the OAuth access token that the client provided in the request), which the mapping from GraphQL-to-application-code can pass to the application code's access controls.


GraphQL queries are hierarchical so that the response mirrors the structure of the query. We found that there were needs of the query (query parameters and directives, for example) that didn't feel ideally represented in JSON, which is why we have a different syntax.

We've got a reference lexer and parser in JS at https://github.com/graphql/graphql-js/tree/master/src/langua..., and we have a parser in C++ with C and C++ APIs (that can be used to build a parser for other languages) at https://github.com/graphql/libgraphqlparser.


Anecdote: when Relay/GraphQL were first announced, we tried to get Relay without GraphQL by writing JSON. This had some advantages (a query was a valid/renderable response!)

...but we had some really ugly JSON. It was worth it for us to get the readable syntax to just use GraphQL.

With client tooling like GraphiQL and editor plugins, it should just get better.


Yep, GraphQL is agnostic as to how your data is stored. For example, https://github.com/graphql/swapi-graphql/ is a GraphQL schema that is backed by the swapi.co API. The examples at https://github.com/graphql/graphql-js/blob/master/src/__test... are backed by in-memory JSON objects. At Facebook, we have GraphQL types backed by data stored in a number of backends, including types backed by SQL tables.


I'd like to read more about the backing data stores. If you're aggregating data across a lot of different stores, it seems you could easily add what looks like a tiny piece of data to your query, but, in truth, is much more expensive on the backend.


It's important to realize that you're essentially defining an API for your product. If something is expensive to access, you should either not expose it directly through your API, or add appropriate levels of caching to mitigate the costs.


It's passed to that function in the reference implementation, but a server would probably create a helper function that runs a query for a particular schema. For example, you can just pass a query to Facebook's GraphQL endpoint (without specifying a schema), and it will run the query on the Facebook schema.


This is also reasonable; but an example of how schema get created and discovered by a client would be a nice extension to the spec. :)


GraphQL doesn't prescribe a particular approach to mutations; it allows the server developer to specify what mutations are available. For example, at Facebook we have a storyCreate mutation, and a friendRequestAdd mutation.

Mutations are just top level fields, but with side effects; because they are fields, the client sends up a selection set with the mutation. This allows the client to receive whatever data it needs to refresh, as the response to the mutation.

GraphQL was originally designed for reads, but we added write support to solve the parallel problem we were having with writes: different clients wanted different data back from the server after they performed a write. GraphQL gave us that capability.


Awesome, thanks for the explanation. My team is rolling out an REST API currently and I've always wanted a Linq/SQL type of interface to REST API's. I could definitely see GraphQL evolving in that kind of direction. Some amazingly cool open source tech coming out of Facebook these days.


I'd suggest that you be wary of going down the route of making your API too flexible. It becomes very difficult to scale up a service that provides flexibility.

Imagine a simple case where you're storing hundreds of records of users, and providing the flexibility to order by any field on the user, and of course, you're paginating those results. Now, scale up; you're storing tens of millions of those same record... how do you quickly retrieve the first ten records ordered by their e-mail address field? Same thing, ordered by their last name. Same thing, ordered by their country. Did you just create database indexes to support each of those use cases? Ugh.

In my opinion, a REST API (well, any API) should be limited to supporting only the business use-cases it is designed to implement. I wouldn't want to build a "Linq/SQL" type of interface, because then I have to support all the weird queries people will come up, and still meet my requirements to scale over time. Don't provide this kind of flexibility unless the value it gives your product is absolutely incredible, because, the headaches it provides could be equally incredible.


> Imagine a simple case where you're storing hundreds of records of users, and providing the flexibility to order by any field on the user...

You don't have to allow ordering by any field. You can define a list of fields that you can order by, and only allow those. I don't see the problem with doing that. But if you must allow ordering by any field...

> Did you just create database indexes to support each of those use cases? Ugh.

...then yes, you would need to do that.

I think the cool thing about GraphQL (at least from my understanding) is it doesn't necessarily give you full power to query data in any arbitrary way from the client--it just provides a more flexible interface for defining what data you want returned from the API and how you want that data structured. It doesn't necessarily have to be a 1:1 mapping of your DB schema, and in most cases I don't think it should be.


This is a great sum-up of a point I often find myself making a lot when explaining GraphQL. GraphQL is only capable of doing exactly what the server-side developer lets it. Order-by is a really great example. We can sort by only the things that make sense to sort by, and often at Facebook we're sorting by heuristics like "sort my friends by how likely I am to send them a message" when loading the friends in a typeahead for chat, and this idea of "message send likelihood" is not exposed as a field.


Maybe OData?


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: