Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2 API RFC #4

Open
thebigredgeek opened this issue Apr 24, 2017 · 28 comments
Open

v2 API RFC #4

thebigredgeek opened this issue Apr 24, 2017 · 28 comments
Labels

Comments

@thebigredgeek
Copy link
Owner

List ideas here

@thebigredgeek
Copy link
Owner Author

#3

@scf4
Copy link

scf4 commented May 18, 2017

Since regular functions work as resolvers, e.g.:

const allPosts = (_, args, ctx) => { ... };

Is the only purpose of createResolver to allow you to compose resolvers from other resolvers?

If so, I propose the following API:

import { composable } from 'apollo-resolvers';

const deleteUser = (_, args, ctx) => { ... };
const editUser = (_, args, ctx) => { ... };
const followUser = (_, args, ctx) => { ... };
const unfollowUser = (_, args, ctx) => { ... };
const banUser = (_, args, ctx) => { ... };
const user = (_, args, ctx) => { ... };

const isLoggedIn = composable((_, args, { user }) => {
  if (!user) throw new Error('Please log in.')
});

const isAdmin = composable((_, args, { user }) => {
  if (!user.isAdmin) throw new Error('Unauthorized!');
});

export default {
  Query: {
    allPosts,
    user: isLoggedIn.compose(user),
  },
  Mutation: {
    followUser,
    unfollowUser,
    isAdmin.compose({
      deleteUser,
      editUser,
      banUser,
    })
  },
};

As for baseResolvers, perhaps combineResolvers could take an optional baseResolver parameter and compose it with every other resolver?

export default combineResolvers([
  postResolvers,
  userResolvers,
], { baseResolver });

This would result in far more manageable code IMO! 😃

@thebigredgeek
Copy link
Owner Author

I think this is a solid direction, but I also think there is value in handling errors as the "bubble up", so we should probably also support error resolvers in the same way that createResolvers allows.

@scf4
Copy link

scf4 commented Jun 10, 2017

I also think there is value in handling errors as the "bubble

How so? How does it differ from errorResolver.compose(newResolver) or using an errorResolver as a baseResolver with combineResolvers?

@thebigredgeek
Copy link
Owner Author

Well, regular resolvers are unidirectional. The request pipes down from source to sink. Errors are handled after the sink throws an error, and they bubble back up in the reverse order.

Repository owner deleted a comment from ch-andrewrhyne Jul 20, 2017
@thebergamo
Copy link

These resolvers act like Middlewares, I think the idea of composable resolvers is really good.

Keeping the "middleware" idea in mind, in Express you can use an error resolver at the end. But based on @thebigredgeek comment, the resolvers are resolved in the reverse order in error cases. Instead of extending a baseResolver you can just put it as a simple function at a position 0 of an array of these middlewares it will be simple, reusable and manageable.

// userResolver.js
import { composable as applyMiddleware } from 'apollo-resolvers';

import { isAuthenticated, isAuthorized } from '.,/middlewares';

const updateUser= (_root, args, context) => { /* do your stuffs here */ };

const userResolver = {
    Mutation: {
        updateUser: applyMiddleware([ isAuthorized, isAuthenticated, userResolver ]),
    }
}

export default userResolver;

And the error resolver is only required in a single point of application. This makes sense for you guys?

@ch-andrewrhyne
Copy link
Collaborator

@thebergamo that's an interesting approach, but how would you implement an error resolver in this case?

@ch-andrewrhyne
Copy link
Collaborator

@scf4 Sorry, I've been busy at my new job. Just starting to get back into focusing on GraphQL. I had to set up a bunch of NodeJS infrastructure first haha. I'm all for a more elegant API. So long as you can pass resolvers returned from createResolver into the compose method, and the compose method will handle the error resolver composition along with the fetch resolver composition, I think this is a great approach. I'd like to ship V2 by end of September. Would you guys like to help me implement this?

@ch-andrewrhyne
Copy link
Collaborator

#11

@ch-andrewrhyne
Copy link
Collaborator

For V2, I'd also really like to refactor into typescript to make the project more developer friendly as we extend the lib's functionality.

@thebigredgeek
Copy link
Owner Author

^ this is me, by the way haha. I have a second account for work

@thebergamo
Copy link

Hey @thebigredgeek I can help, just need to learn a little bit more about TypeScript.

Well, the idea of the error handler, is to have a simple function like express middleware, but in the case of express you register the middleware for error at the end chain of middlewares.

const errorHandler = (err, ...params) => {/* when an error occur, this function must to be called */};  

And in this case, will be really good if this handler can be declared just once.

@scf4
Copy link

scf4 commented Aug 31, 2017

@thebergamo @thebigredgeek how about Flow instead of TS?

@scf4
Copy link

scf4 commented Aug 31, 2017

Also, how would you feel about expanding the scope of this project to become more of a library (or very small and fairly unopinionated framework) for building GraphQL server apps with Apollo?

It's surprisingly difficult to find info on best practices and solving common problems with JS GraphQL APIs. You're really on your own, especially compared to what's available on the front end. There's a lot of reinventing the wheel.

The JS GraphQL community could seriously benefit from something like this.

@thebergamo
Copy link

@scf4 I don't know what the @thebigredgeek thinks about expanding this project to something more. IMHO is better keeping this module focused on this and create a new one to be the library to build GraphQL APIs.

It's really really hard to find best pratices for somethings :p

@ms440
Copy link

ms440 commented Sep 3, 2017

@thebigredgeek Nice package! Thanks!

The only reason I'm not using it right away is that in V.1 the baseResolver does not have an info argument. The same about createResolver function... :(

Why wouldn't you push V2 to npm (with, say, V1.1)? It won't break the backward compatibility, it's an additional feature. Meanwhile, V2 work will go on.

Anyway, thanks a lot.

@thebigredgeek
Copy link
Owner Author

I'm building a framework called Edge at Collective Health (my awesome new job) that will take away a lot of the boilerplate for building microservices with NodeJS, including with GraphQL, with a decorator-based DSL for defining GraphQL types, resolver bindings, etc. I'll write a blog post about it and stick it in the README once it's getting closer to finished

@ch-andrewrhyne
Copy link
Collaborator

@scf4 Not sure on Flow. I've used it before and I like it, but Typescript removes almost all of the developer tooling boilerplate (babel, etc). I am on the fence about using Flow rather than typescript. Would love more insight into your thoughts about this.

@thebigredgeek
Copy link
Owner Author

One change we are making is adding the info prop for resolvers. #9

@thebigredgeek
Copy link
Owner Author

#20

@thebigredgeek
Copy link
Owner Author

Typescript support is implemented!

@thebigredgeek
Copy link
Owner Author

If anyone wants to implement a compose method for resolvers, I'm happy to review a PR!

@mringer
Copy link
Contributor

mringer commented May 14, 2018

@thebigredgeek posted my first pass at compose in #31

@ak99372
Copy link

ak99372 commented Jul 30, 2018

@thebigredgeek Has #11 been implemented?

The current version of [combineResolvers] has a different signature and I can't seem to figure out how to use it.

It would be nice if it allowed to add resolver(s) to another or a group of existing resolvers (that already have a base)

combine(r1, r2)with(r3, r4)

@mringer
Copy link
Contributor

mringer commented Jul 30, 2018

@ak99372 take a look at #31

@mringer
Copy link
Contributor

mringer commented Aug 2, 2018

@thebigredgeek I've been getting Circle CI notifications about v1 API depreciation. I'm planning to refactor the circleci.yml to conform to the v2 API sometime this week, time permitting. In any case we have till the end of the month before they drop support for v1.

@thebigredgeek
Copy link
Owner Author

Just saw your PR! Nice job

@thebigredgeek
Copy link
Owner Author

For those interested, I'm modernizing this package here: #67

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants