Code Monkey home page Code Monkey logo

apollo-resolvers's People

Contributors

alexstrat avatar ch-andrewrhyne avatar doomsower avatar giautm avatar happylinks avatar lakhansamani avatar michieldewilde avatar mringer avatar n1ru4l avatar renovate-bot avatar rynobax avatar thebigredgeek avatar theglenn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

apollo-resolvers's Issues

Pass data among resolvers

Hi. I recently used this library and really enjoy it. I wonder if there's anyway if we can pass data from a resolver to another.

For example, let's say I have a resolver isStatusOwnerResolver like this:

export const isStatusOwnerResolver = isAuthenticatedResolver.createResolver(
  async (root, { statusId }, { userId, models: { Status } }) => {
    const status = await Status.findById(statusId)
    if (status.ownerId.toString() !== userId) {
      throw new NotStatusOwnerError()
    }
  },
)

Is there anyway I can pass status to the resolver that is chained from isStatusOwnerResolver?

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • chore(deps): update dependency eslint to v9
  • chore(deps): update dependency mocha to v10
  • chore(deps): update dependency rimraf to v5
  • chore(deps): update dependency sinon to v17
  • chore(deps): update dependency typescript to v5
  • chore(deps): update node.js to v17
  • ๐Ÿ” Create all rate-limited PRs at once ๐Ÿ”

Edited/Blocked

These updates have been manually edited so Renovate will no longer make changes. To discard all commits and start over, click on a checkbox.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

circleci
.circleci/config.yml
  • circleci/node 8
  • circleci/node 10
  • circleci/node 12
  • circleci/node 14
npm
package.json
  • assert ^2.0.0
  • deepmerge ^3.0.0
  • babel-cli 6.26.0
  • babel-core 6.26.3
  • babel-eslint 7.2.3
  • babel-plugin-transform-object-rest-spread 6.26.0
  • babel-preset-env 1.7.0
  • babel-register 6.26.0
  • bluebird 3.5.4
  • chai 3.5.0
  • eslint 3.19.0
  • eslint-plugin-babel 3.3.0
  • express 4.16.4
  • graphql-server-express 0.6.0
  • mocha 3.5.3
  • rimraf 2.6.3
  • sinon 1.17.7
  • supertest 3.4.2
  • typescript 2.9.2
  • typings 2.1.1

  • Check this box to trigger a request for Renovate to run again on this repository

[Examples, Question] for database connection errors using MongoDB + apollo-errors + apollo-resolvers

Hello there!

This is what I did in order to handle database connection errors using MongoDB and 2 awesome packages
apollo-errors and apollo-resolvers.

First of all I created a middleware that handles the connection to MongoDB where the client is a promise that resolves to the Connected client and the db is the database instance.

Note that I am calling the next middleware even though there is an error or not and the same time attaching the client and the db instance to request object in order to be available in the context object, here is where I'm not sure if is safe or bad doing it in this way because in my case I'm doing a signup form and well I need to open a connection to the database every time the user makes a request.

const dbConnection  = async (req, res, next) => {
    try {
        const client = await MongoClient.connect('mongodb://localhost:27017')
        const db = client.db('myproject')
        req.client = client
        req.db = db
        next()
    } catch (error) {
        req.err = error.message
        next()
    }
}

app.use('/graphql', dbConnection, bodyParser.json(), graphqlExpress(req => {
    return {
        schema,
        formatError,
        context: {
            client: req.client,
            db: req.db,
            err: req.err
        }
    }
}))

Then I create a base resolver for unknown thrown errors and another one that get all the users from the database, note that in the last resolver I am checking if there is an error, again I don't know if is good or bad doing it this way.

const baseResolver = createResolver(
    null,
    (_, args, context, error) => {
        if (isInstance(error)) return error
        return new UnknownError({
            data: {
                message: 'Oops! Something went wrong'
            }
        })
    })

const getAllUsers = baseResolver.createResolver(
    (_, args, {
        client,
        db,
        err
    }) => {
        if (err) throw new DatabaseConnectionError({
            data: {
                message: err
            }
        })
        return ...
    })

const resolvers = {
    Query: {
        getAllUsers
    },

I could do this directly in a resolver called dbConnectionResolver and throw erros from there and spam getAllUsers from the previous one like so: const getAllUsers = dbConnectionResolver.createResolver(...) the problem though is if there is no errors thrown in the dbConnectionResolver I don't get access to the client and the db instance in the next resolver.

Surely I'm doing something wrong because of my lack of knowledge if somebody have some thoughts on this I'll appreciate it. Thanks.

Resolvers don't pass info

As best as I can tell, this implementation of resolvers does not pass along the info argument from Apollo's resolver signature. This breaks my usage of fieldASTs to skip unnecessary DB joins in the resolvers.

This would be a breaking change, but would you consider changing your resolver signature to match Apollo's? My use case represents only one of the many useful things that can be done with info.

resolver(root, args, context, info, errors) {}

Example of baseResolver error callback

Hey lib is great! Have a question regarding errors thrown. Can you provide an example of handling the errors, I'd like to catch them before it is passed to the client and I'm struggling to find best way.

Thanks,
ron

Error after updating to 1.1.0

On building with typescript, this error message is presented
error TS2339: Property 'createResolver' does not exist on type '(root: any, args?: {}, context?: {}) => Promise<any>'.
Is there anything that needs to be updated?
I've reverted to 1.0.3 for now

Option to stop error bubbling

Epic library!

The problem is this. When my custom base resolver has handled the error and returns it, it is thrown which leads to an unhandled error in the runtime.

Is it necessary to catch the error in the endpoint resolver? In that case, shouldn't there be an option not to throw the error?

For example, if I have an authResolver, I don't want to have to catch the UnauthorizedError every time I create a resolver with it.

Or is there any other best practise of this?

EDIT
Turns out I've misunderstood the graphql flow. It was graphql itself that threw the error so there cannot be an option for this. To get rid of the thrown error set graphqlOptions.debug = false

Minor typescript issues

All of them can be worked around with any and !, but it would be nice to see them fixed here.

First one:

export interface CreateResolverFunction {
  <R, E>(resFn: ResultFunction<R>, errFn?: ErrorFunction<E>): Resolver<R>
}

export const createResolver: CreateResolverFunction 

Probably resFn should be optional or nullable, because in your examples you use it like this:

export const baseResolver = createResolver(
   //incoming requests will pass through this resolver like a no-op
  null,

  /*
    Only mask outgoing errors that aren't already apollo-errors,
    such as ORM errors etc
  */
  (root, args, context, error) => isInstance(error) ? error : new UnknownError()
);

Or maybe there should be two types, one for module-level createResolver and one for Resolver's createResolver

Second is that you define Resolver as

export interface Resolver<ResulType> {
  (root, args: {}, context: {}, info: {}): Promise<ResulType>
  createResolver?: CreateResolverFunction
  compose?: ComposeResolversFunction
}

As far as I get it, the only way to create resolver is via createResolver and it will always add createResolver and compose, so they shouldn't be optional in interface.

Nullable returns

Is it expected that returning null from a resolver should allow the request to continue to the child resolver?

Since null is a valid return type for nullable fields, it may be desired that a resolver returns an early null like so.

eg.

const isAuthenticatedResolver = baseResolver.createResolver(
  (root, args, { isAuthenticated }) => {
    if (!isAuthenticated) return null;
  }
);

Passing info to Resolver

I got this error because info not passed to resolver. :(

TypeError: Cannot read property 'parentType' of undefined

on graphql-relay globalIdResolver

    (obj, args, context, info) => toGlobalId(
      typeName || info.parentType.name,
      idFetcher ? idFetcher(obj, context, info) : obj.id
    )

Restify + GraphQL + Apollo + Firebase Auth Possible?

Hi, i'm right now studying those themes mentioned above. That's the question (above).

I'm creating a simple GraphQL API structure to learn about it. And I wish to integrate it with Firebase Auth. Couse I'm studying about the Auth from FB to use in a React Native client.

And I'm venturing into Restify xD

Many thanks,

Best Regards.

Dist is broken

It would appear that the dist file index.js is missing everything except combineResolvers and usePromise. This is the case for 1.0.0 and 1.0.1. That makes the library unusable via NPM or Yarn.

I'm guessing it could be something in the build process.

4th resolve parameter: info

Can you please add the 4th parameter to createResolver. The info object contains some useful information when attempting to create more advanced resolvers.

Wrong resolvers condition when or(true, false) and final resolver throws

Hi, funny thing. Not all cases are covered in tests and there is a bug with one of these.
Here is an example of test with or condition:

// test/unit/helper_spec.js
it('when (true, false) and resolver throws, it should return exactly that error', () => {
        const resolver = or(successResolver, failureResolver);
        const testError = new Error('test');
        const finalResolver = resolver(() => {
          throw testError;
        });
        return finalResolver()
          .catch(err => {
            expect(err).to.equal(testError);
          });
      });

So, if first resolver succeed it immediately runs query. But if query throws, second resolver runs after that and if it is throws, we receive that second error, but not the error that query throws

Recommended way of passing information to the next resolver?

I'm wondering what's the best approach to achieve the following behaviour:

1st resolver: Checks if user is authenticated
2nd resolver: Checks if user has permissions to edit the document. Since we already fetched the document in this step to check permissions, it would be nice to be able to pass the document to the next resolver.
3rd resolver: Query or make the changes to the document in question.

This is what my resolvers look like so far:

const isAuthenticatedResolver = createResolver((root, args, { user }) => {
  if (!user) throw new UnauthenticatedError();
});

const isInOrganization = isAuthenticatedResolver.createResolver(
  (root, { organizationId }, { user }) => {
    return Organization.findOne({ _id: organizationId, owner: user.id })
      .then(organization => {
        if (!organization) throw new CustomError('Please check you have permission to access this organization');
        // How do I pass organization to the next stage?
        // I tried `return`ing organization at this point, but that resolves[?] the resolver and prevents
        // the next one to be executed.
      });
  }
);

const RootResolver = {
  getMembers: isInOrganization.createResolver(
    (organization) => organization.getMembers()
  )
}

apollo-resolvers as subscription "subscribe"

Hi,
is it possible to use apollo-resolvers as subscription resolver?

I noticed in this case the context is not passed to resolver.

export const resolvers = {
	//...
	Subscription: {
		status: {
			subscribe:
				isAuthenticatedResolver.createResolver(
					(_, args, context, info) => {
						//...
					}
				),
			resolve: ({ data }) =>
				//...
		}
	}
};

Typescript - TypeError: Cannot read property 'createResolver' of undefined

The following error is occurring when trying to use apollo-resolvers with typescript, I noticed that several people were having the same problem and I decided to open the issue, more details below.

Error

captura de tela 2018-12-14 as 15 19 00

resolvers

captura de tela 2018-12-14 as 15 22 56

userResolvers

captura de tela 2018-12-14 as 15 20 51

package.json

  "dependencies": {
    "@sentry/node": "4.4.2",
    "apollo-errors": "1.9.0",
    "apollo-resolvers": "1.4.1",
    "apollo-server-micro": "2.3.1",
    "bcryptjs": "2.4.3",
    "bluebird": "3.5.3",
    "ccxt": "1.18.36",
    "date-fns": "1.30.1",
    "dotenv": "6.2.0",
    "graphql": "14.0.2",
    "i18nh": "0.0.4",
    "idx": "2.5.2",
    "jsonwebtoken": "8.4.0",
    "micro": "9.3.3",
    "micro-compose": "0.0.3",
    "micro-cors": "0.1.1",
    "mongoose": "5.3.16",
    "ramda": "0.26.1",
    "ts-node": "7.0.1",
    "validator": "10.9.0"
  },
  "devDependencies": {
    "@types/bcryptjs": "2.4.2",
    "@types/bluebird": "3.5.25",
    "@types/dotenv": "6.1.0",
    "@types/graphql": "14.0.3",
    "@types/jsonwebtoken": "8.3.0",
    "@types/micro": "7.3.3",
    "@types/micro-cors": "0.1.0",
    "@types/mongoose": "5.3.5",
    "@types/ramda": "0.25.43",
    "@types/validator": "9.4.4",
    "husky": "1.2.1",
    "lint-staged": "8.1.0",
    "nodemon": "1.18.8",
    "prettier": "1.15.3",
    "tslint": "5.11.0",
    "tslint-config-prettier": "1.17.0",
    "tslint-config-security": "1.13.0",
    "typescript": "3.2.2"
  },

Static type testing in TS not working: error 2339

Example:
When calling function createResolver from baseResolver TS reports an error.
error TS2339: Property 'createResolver' does not exist on type '(root: any, args?: {}, context?: {}) => Promise'.

Example code readme.md
export const isAuthenticatedResolver = baseResolver.createResolver(

Project Housekeeping

Figured I'd add a couple housekeeping items.

  1. Make master a protected branch and add 'requite all status checks pass to merge'.
  2. Enable 'Require reviews to merge'.

Deploying using apollo-server-lambda

Do you have a deployment that isn't using express? We can't use express as we have to use Serverless and I'm a little confused to the correct way to get this working inside an apollo-server-lambda environment

Async function in a parent resolver

Hi,
is it possible to use an async function in a parent resolver?

I'm trying to achieve something like this:

export const isAuthenticatedResolver = baseResolver.createResolver(
	(_, args, { token }) => {
		if (!token) {
			throw new AuthenticationRequiredError();
		}

                 //async part here
                 db.models.sessions.query(token)
                     .catch(e => throw new InvalidTokenError() )
);

Granular errors?

Hi, first let me say thank you for creating this library. It's been a very useful design pattern.

Today I've run into the problem with trying to authenticate a query that looks something like this:

query {
  open
  sensitive
}

where open is clear to anyone, but sensitive requires certain permissions.

It seems when I throw an error using the apollo-resolvers pattern, the data for open never makes it to the client. On the bright side, the "errors" data is correctly in the response.

Is it possible to have both the error data and open data in the same response using this library?

Improve typings

Hello,

I'm wondering if there is a way to improve the typings definition by having the context variable being typed :

export interface ResultFunction<ResulType> {
    (root: any, args: any, context: any, info: any): Promise<ResulType> | ResulType | void;
}

becomes

export interface ResultFunction<ResulType, ContextType> {
    (root: any, args: any, context: ContextType, info: any): Promise<ResulType> | ResulType | void;
}

The idea behind that is that if we make some modifications on the context object (like adding new properties that would be needed by the next resolver in the pipe), we would then be able to retrieve a fully typed variable in the next resolver, instead of any.
In a perfect world, each resolver context type should augment the previous one, so that the last resolver gets a merged type of all added properties.

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.