Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Apollo Server 1.0  – GraphQL Server for Node.js Frameworks (apollodata.com)
159 points by michaelsbradley on July 20, 2017 | hide | past | favorite | 43 comments


I never quite understood Apollo. I've written GraphQL servers using just the Node.js GraphQL implementation and they haven't been much code. Barely more boilerplate than the Apollo example given.

I'll have to dive into the code myself when I have some free time but can anyone explain to me what value this adds specifically?

I am assuming it does add value and I'm just not seeing it.


From the doc:

Comparison with express-graphql

- express-graphql works with Express and Connect, Apollo Server supports Express, Connect, Hapi, Koa and Restify.

- Compared to express-graphql, Apollo Server has a simpler interface and supports exactly one way of passing queries.

- Apollo Server separates serving GraphiQL (an in-browser IDE for exploring GraphQL) from responding to GraphQL requests.

- express-graphql contains code for parsing HTTP request bodies, Apollo Server leaves that to standard packages like body-parser.

- Apollo Server includes an OperationStore to easily manage whitelisting.

- Apollo Server is built with TypeScript.


Thank you for digging that up. You don't need to use express-graphql to use graphql on a server so that comparison is only meaningful if you already use a wrapper... I'm was curious why a wrapper is even needed. The base GraphQL.js library is not complicated.

The Apollo team member himself even said the wrapper is "thin."


Hey, I'm on the Apollo team! As mentioned in the blog post, this is just a thin wrapper around the regular GraphQL.js implementation, with a few small bells and whistles added!

The intention of this library isn't to change a lot about how GraphQL servers are written, it's just a stable, community focused library to bind your GraphQL server to a schema.


Hi djmashko2, thank you for your reply and keep up the good work.

I'm not sure that answers my question though. I'd like to know which things it makes easier. Maybe a side by side with the "traditional way" vs "the Appolo way"

Looking at the website, it looks like it makes the benefit of Apollo client relatively clear, I'm still not sure about the server piece.



So we now have React/Webpack + Redux + Apollo + GraphQL + Node + Pogstgres where once we had Rails/PHP/Django + Postgres. Someone hit me over the head because I don't get how all this is progress. There's no way I can teach web development to a beginner if there are so many layers between request and response.


What follows is just IMO.

Rails/PHP/Django embody the MVC paradigm, where in reality it's just model and controller, and very little view.

React+Redux is bringing view to another level, and node is there just so you can render server-side the same things you render in the browser. When I saying bringing to another level, I don't just mean it's more feature-rich, I mean it's more maintainable, testable, and it's a paradigm designed to scale the team working on it by reducing complexity.

Back to the MVC comparison, Apollo+GraphQL bring the same concept of evolution to the API (controller maybe?). In the MVC world you learn how to build one API, not how to keep it working, maintain and upgrade it for years. GraphQL is a solution to that, Apollo (as said in other comments) is just a tiny layer.

Finally, the model in the MVC to me is just an academic abstraction, I've seen 0 large-scale deployments using joins and integrity constrains.

So yes, before it was MVC, with different implementations in different languages, now people are looking into JS because it's supported in the browser and moving towards more scalable architectures, both in terms of infrastructure and team.


If you're making a 4 page brochure website, you can use react or rails. A beginner can handle that. If you're making a full web application where the user interface had good UX and is performant with non-trivial user interface logic and also there is non-trivial backend logic and eventually you would like to release mobile apps, I don't think you should expect to be able to teach a beginner all of that. But using react+express (I prefer feathersjs, but you can sustitute rails or any other backend) will be the shortest path to the more complicated scenario I mentioned.

Your comment is based on a grossly misleading presentation of the comparison though. React is a powerful view layer with an ecosystem around it. Rails is a full framework. You've misrepresented rails as simple and easy to learn by using only one term to describe it, and misrepresented the alternative to rails by separating it's components into named parts to scare us into thinking "Wow, 7 things? That's way more complicated than 2 things!" The reverse misrepresentation would be "So we now have react + postgre, but you're still using rails router + rails templates + rails graphql + rails rest + rails ORM + rails http client + jQuery + jQuery UI + gem + Ruby + macbookpro. How can you manage to train anyone on so many complicated tools?"

Why is this progress? Rails has it's limits in terms of full potential (complicsted backend + complicated UI + fast path to cross platform apps). You can add react to rails and reach the full potential. You can also do less than the full potential without react. React has some alternatives growing to also give you full potential, some not even in JS. It's 100% progress all across the board.


I don't really understand this criticism. If your web app is simple/static enough, then by all means use Rails. Everything will be simpler. But there are an entire class of applications that can't be built with that stack.


That's a very bold statement: "can't be built with that stack".

A large portion of apps aren't built with Node or React, they're built with, say, Rails, Java/Spring or .NET backends and a front end framework like Angular.

I get the theory behind React, the reality is that it is often a complete mess.


Since when was Rails limited to "simple/static" sites? I see the opposite all over the place these days - React + entourage for the most basic dynamic sites.


I totally agree! We keep adding more layers to the web stack. Even Django and Rails themselves were added complexity!

I've actually built a solution to this problem called Statebus: https://stateb.us

It takes a unique approach to the problem — instead of building more layers in the web stack, it builds support for change directly into HTTP itself! It turns out that if HTTP supports changing pages, and keeping things synchronized, you don't need web frameworks at all anymore.


What part of this made you think that you had to use it much less a beginner? Is it because it exists at all?

Hard for me to see that as a problem with the tools rather than the developer.


Check out the jobs. React + entourage is all over the place. If I'm teaching a beginner who wants to enter the job market he's going to have to learn the whole stack.


Only if the beginner wants to get into richer client-side applications, which is only part of the whole web application market. And GraphQL is rare.

There are plenty of 100% server-side jobs. Maybe you should be pointing those out to beginners instead of suggesting that they need to learn even niche tech like GraphQL before having a shot in the job market.


you're right there is a lot of tooling/layers

if it helps, Apollo has Redux built into it so you don't need a store. With this I reduced the size of my small app quite significantly by removing reducers, actions and the store files.

I've been using React + Apollo + GraphQL on the frontend and Graph.cool as a BaaS which has been great so far.... admittedly I'm a beginner (starting from my experience as a Java developer 7 years ago)


Couldn't find if Apollo solves the database round trips issue with GraphQL (the joins/n+1 problem). Can anybody shed a light on it?


There are basically two approaches to this issue:

0) Do nothing

If you are just prototyping, you should do the simplest thing that could possibly work. (But this is not a real solution, so I won't count it)

2) Request Batching

This approach is popularised by Facebooks Dataloader library https://github.com/facebook/dataloader Instead of directly querying the database in the resolver, you return a specification of what data you are interested in. When all resolvers on the same level in the query has returned this specification, the Dataloader library figures out how to batch queries together as much as possible

3) Big Join

You can inspect the GraphQL query in the top level resolver and basically perform one giant join up front. You will then pass the entire value down your resolve hierarchy, and all they have to do is pick out the correct data from the complete result set. Take a look at join-monster if you are interested in this approach.

The Graphcool hosted backend is serving millions of requests an hour using the Dataloader approach, and we have found this to be more flexible and more performant at scale than generating a big complex join up front.

For most queries we see single digit millisecond response time for a batched query, and the time complexity scales linearly with the depth of the query, which is not the case for joins.


The GraphQL compiler project also implements the 3) approach: https://github.com/kensho-technologies/graphql-compiler

Primer on how to use it: https://blog.kensho.com/compiled-graphql-as-a-database-query...

Full disclosure: I wrote it, and open-sourced it just yesterday.


2) is easy, but leads to two queries no matter what, because you have to do a whereIn

3) here's the code:

const EagerQL = (info, allowed) => { let fields = info.operation.selectionSet.selections[0].selectionSet.selections; return fields .map(field => field.name.value) .filter(field => allowed.includes(field)); };

// in a resolver user(_, args, context, info) { let eagers = EagerQL(info); console.log(eagers); // ['posts'] }

This will give you fields that were queried for so you can do a big join. Hope this helps someone :P


trying to access fields like `info.operation.selectionSet.selections[0].selectionSet.selections` always feel wrong to me. I wish graphql library part comes with some utility function for these.


Completely agree.... I don't understand why there isn't a more standard way of accessing the fields queried for so that you can do joins.


It does not-- we've been using graphql intensively with relationship-heavy graph data and join-monster seems handle this gracefully.

join-monster.readthedocs.io


Wow! Thank you, I have been looking for something like this. I use mostly NoSQL which typically doesn't do joins (unless it is a graph database) but this looks really usefully for when I do have a SQL database to work with.


If you use a graph database, something like the GraphQL compiler project might be useful: https://github.com/kensho-technologies/graphql-compiler

Primer on how to use it: https://blog.kensho.com/compiled-graphql-as-a-database-query...

I work at Kensho and we use it with queries that are 10+ levels of nesting with no problems.


Interesting approach for using GraphQL with a graph database. There is also an integration for Neo4j [1] that works similarly (it translates GraphQL to Cypher), however it also exposes Cypher in GraphQL through a @cypher directive, which maps complex graph traversals/aggregations to a single GraphQL field.

[1] https://www.npmjs.com/package/neo4j-graphql-cli


it's a great solution as long as your queries are no deeper than 2 levels


@tylerbainbridge and I work at Conduit (https://conduithq.com), where we are using GraphQL, join-monster, and PostgreSQL in production.

What you describe isn't a limitation at all-- some of our queries run 10 levels deep and work just fine. In fact, this method is so powerful that most of our queries start from the `user` object and just JOIN off of it.


agreed. If people understand what Join Monster does then they'd see it is still suboptimal in a world where we have Postgres and LATERAL :-D


Haven’t read enough into lateral joins myself, but if set to pg dialect, join-monster uses lateral joins for pagination: http://join-monster.readthedocs.io/en/stable/dialects/

I’m sure they’d welcome further feedback or pull requests...


It's a lib working at a higher level so things like n+1 are left to be solved by the user since the implementation details depend very much on the underlying data storage.

If you use PostgreSQL however, i solve that problem :) https://subzero.cloud (GraphQL & REST api for your database) It's still in private beta but you can get a sense of how things are put together by looking a this OS project (just REST) https://github.com/subzerocloud/postgrest-starter-kit


I think this is something that graphql implementations are still trying to figure out. At work (samsara.com) we use a time-based batch[0] for our queries to help with n+1 issues in our graphql server.

Separate branches of the the graphql query are handed to independent goroutines. When batchable rpcs (to the database, or other services) occur, we delay execution by ~1ms and wait for any other rpcs of the same type (and keep delaying for up to ~20ms). This works pretty well for our more expensive field resolvers. We've also thought about ways to examine and track the execution of the goroutines (similar to the facebook/dataloader approach), but the time-based batches have worked pretty well for us so far.

We also aggressively cache queries and rpcs so that the same data is not expensive to fetch across different branches of a query.

[0] You can see the batching implementation here: https://github.com/samsarahq/thunder/blob/master/batch/batch...


N+1 problem?

Old timers that remember Enterprise JavaBeans 1.x entity beans are probably rolling in laughter currently. It had a very similar problem in 1999-2000 that doomed many systems to crappy performance and tarred EJB forever.

History never fails to repeat itself: beware subsystems that propose to wrap and abstract your database for a new paradigm "automatically". They're leaky and difficult and take a decade to get right. See: ActiveRecord, EJB followed by JPA, .NET's various DB frameworks, Django, etc.


I wrote a little proof of concept in JavaScript showing one way of dealing with the problem [1]. Essentially, as you go through each node in the request, build up a query (say, a SQL query) that represents the fetching of that node by joining it with the query of its parent. Then, stitch the result of running each query back onto the result of running the parent query. Conceptually, this means one resolution function call for each node in the request, rather than one resolution function call for each node node in the response.

[1] https://github.com/mwilliamson/node-graphjoiner

However, it's rather verbose with repeated boilerplate, so to make the approach work I think you'd want to put a higher-level layer on top -- that's what I've done with a Python implementation [2]. I think the general approach is the valuable part, rather than the specific libraries, and seems more in keeping with how I'd normally write queries than the usual DataLoader approach. In particular, I've found it tends to improve performance when fetching large data sets since you don't need to call a resolution function on every single field that gets returned. (DataLoader implementations batch queries together to avoid the n+1 problem, but they mean that you need to implement a batching layer, and probably make your resolution functions asynchronous, which is especially expensive for large data sets).

[2] https://github.com/healx/python-graphjoiner


The image is pretty misleading. It looks as if GraphQL server connects you to REST and SQL.

In fact you simply have functions called resolvers where you write your logic to get data from wherever you want. SQL, NoSQL, API, filesystem, etc.


I think the idea is that you shouldn't want to have GraphQL server code containing business logic code in it.

GraphQL should just be proxy layer between actual client and the actual, multiple, APIs.


But then why connect it to SQL and Redis?


Yeah the diagram is intended to represent where GraphQL usually sits in your architecture.


Is this a direct replacement for graphql-server-express?

I've been using it while following along the backend JS tutorial at howtographql.com and was wondering if it's now outdated and what the migration would look like.


It's exactly the same thing but renamed - we're going to make both names work for a few weeks and then deprecate the graphql-server name after all the resources are updated. It's exactly the same, just change your import to "apollo-server-express"


Awesome! I would suggest updating your documentation, as there are some places where the graphql-* variant is mentioned.


Just did it, thanks so much!




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

Search: