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

Overwriting GraphQL schema #1232

Closed
1 task done
raulriera opened this issue May 19, 2018 · 15 comments
Closed
1 task done

Overwriting GraphQL schema #1232

raulriera opened this issue May 19, 2018 · 15 comments
Assignees
Labels
issue: bug Issue reporting a bug severity: medium If it breaks the basic use of the product but can be worked around

Comments

@raulriera
Copy link
Contributor

raulriera commented May 19, 2018

Informations

  • Node.js version: 9.11.1
  • npm version: 5.6.0
  • Strapi version: 3.0.0-alpha.12.2
  • Database: mongo
  • Operating system: macOS

What is the current behavior?
I'm trying to overwrite the GraphQL query from

type Query {
  practice(id: String): Practice
  type: {
    Practice: false
  },
  resolver: {
    Query: {
      practice: {
        description: 'Return the practice of the authenticated user',
        resolver: 'Practice.findMine'
      },
      practices: false
    }
  }
}

to

type Query {
  practice: Practice
  type: {
    Practice: false
  },
  resolver: {
    Query: {
      practice: {
        description: 'Return the practice of the authenticated user',
        resolver: 'Practice.findMine'
      },
      practices: false
    }
  }
}

But running strapi will error in Error: Resolver Query.practice must be object or function

Steps to reproduce the problem
Try to overwrite the default findOne route of any model like the example above

What is the expected behavior?
It should overwrite the schema without a problem, even the generated code looks correct

# generated schema file
type Query {
  patient(id: String!): Patient
  patients(sort: String, limit: Int, start: Int, where: JSON): [Patient]
  practice: Practice # this looks correct, it doesn't have the id: String, argument

Suggested solutions
I don't know any, I'm trying to find a solution myself without success


  • I'm sure that this feature hasn't already been referenced.
@raulriera
Copy link
Contributor Author

raulriera commented May 19, 2018

The issue seems to be about any resolver as a single string value, this will fail in

// GraphQL.js
    const schema = makeExecutableSchema({
      typeDefs,
      resolvers,
    });

because it's literally not a function (in this image, I moved away from trying to rewrite practice which may be another problem, and just trying to create a simple new GraphQL endpoint)

screen shot 2018-05-19 at 12 33 41 pm

Although, this is how the docs say it should work https://strapi.io/documentation/guides/graphql.html

Strangely, changing just the resolver does work, but this is not what I need to do

module.exports = {
  resolver: {
    Query: {
      practice: {
        description: 'Return the practice of the authenticated user',
        resolver: 'Practice.findMine'
      },
      practices: false
    }
  }
};

@lauriejim lauriejim added issue: bug Issue reporting a bug severity: medium If it breaks the basic use of the product but can be worked around labels May 21, 2018
@johannpinson
Copy link
Contributor

Hey @raulriera

I was looking for this bug today and you right, the problem is when you add a string as a resolver.
Moreover, the resolverOf doesn't looks to be applied.


@lauriejim : FYI =>
In the generateSchema function, around this code:

acc[type][resolver] = _.isFunction(acc[type][resolver]) ?
  acc[type][resolver] :
  acc[type][resolver].resolver;

I try to replace it by:

if (acc[type][resolver].resolver &&  _.isString(acc[type][resolver].resolver) {
  const [name] = acc[type][resolver].resolver.split('.');
  acc[type][resolver] = this.composeResolver({}, null, name.toLowerCase(), pluralize.isSingular(name))
}

But i have some problems with the override from the upload plugin (which one works well with the resolver as a string, but it seems because the ShadowCRUD already init it).

@lauriejim
Copy link
Contributor

Hello guys @raulriera and @johannpinson !
Thank you for reporting this issue. We are currently on another feature and bug fix. Since time is lacking on our side, feel free to submit a PR, we’ll appreciate your contribution on this issue!

@Aurelsicoko is the best person to help you on this side - but he has lot of work actually :/

Check out the contributing guide to get started: https://github.com/strapi/strapi/blob/master/.github/CONTRIBUTING.md

@Aurelsicoko
Copy link
Member

Aurelsicoko commented May 24, 2018

Okay, so I fixed this. You can set the resolver in two different way:

module.exports = {
  definition: ``,
  query: `
    practice: [Practice]
  `,
  type: {
    Practice: false
  },
  resolver: {
    Query: {
      practice: {
        description: 'Return the practice of the authenticated user',
        resolver: 'Practice.findMine'
      },
      practices: false
    }
  }
};

or with an object when you have to reach a controller's action which is inside a plugin

module.exports = {
  definition: ``,
  query: `
    user: [UsersPermissionsUser]
  `,
  type: {
    UsersPermissionsUser: false
  },
  resolver: {
    Query: {
      user: {
        description: 'Return the authenticated user',
        resolver: {
          plugin: 'users-permissions', 
          handler: 'User.findMe'
      },
      users: false
    }
  }
};

@raulriera
Copy link
Contributor Author

Oh, that is awesome @Aurelsicoko ... looking at your commit now...

@Aurelsicoko
Copy link
Member

Not sure it will be the last one but it works for this case and it also supports the resolverOf attribute and applies the right policies.

@johannpinson
Copy link
Contributor

Thanks @Aurelsicoko! 👍

@daymont87
Copy link

@Aurelsicoko I found that if i call in resolver default (autogenerated) functions from api/mymodel/controllers/mymodel.js, for example "find: async (ctx)"

resolver: (obj, options, context) => {
          return Mpack.find(obj);
        }

it works fine, but if i create custom function, for example "getPacks" (even with the same code that default "find: async (ctx)" function) - i getting an error "TypeError: Pack.getPacks is not a function". Is it means that i can't call custom functions?

@Aurelsicoko
Copy link
Member

It means that you have to create the custom functions in your controller, then make a reference to it.

@alexandrebodin did you write a test about this use case or not?

@alexandrebodin
Copy link
Member

alexandrebodin commented Apr 2, 2019

@Aurelsicoko Nope I only tested the generate api not the way we generate / overwrite it for now

@daymont87
Copy link

It means that you have to create the custom functions in your controller, then make a reference to it.

@alexandrebodin did you write a test about this use case or not?

How to make a reference (in which directory/file)? Is there information in docs about it?

@alexandrebodin
Copy link
Member

You can find som examples here https://strapi.io/documentation/3.x.x/guides/graphql.html#customise-the-graphql-schema

@merijnponzo
Copy link

merijnponzo commented Jun 24, 2019

Hello,
I'm following the documentation from beta.
The part 'Link a query or mutation to a controller action'

When I try within a custom schema.graphql within api/puppies/config

module.exports = {
  resolver: {
    Query: {
      puppies: {
        resolver: 'puppies.find',
      }
    },
    Mutation: {
      updatePuppies: {
        description: 'updating only by current user',
        resolver: 'puppies.update',
        policy: [],
      },
    },
  }
};

No errors.

The Query does give me the console.log from with the results.
But the mutation is doesnt do anything, or update any values

api/puppies/controller/Puppies.js

find(ctx) {
    console.log('called!');
    if (ctx.query._q) {
      return strapi.services.puppies.search(ctx.query);
    }
    return strapi.services.puppies.find(ctx.query);
  },
  update(ctx) {
    console.log('called updated');
    return strapi.services.puppies.update(ctx.params, ctx.request.body);
  }

@merijnponzo
Copy link

Since it didnt gave me an error it solved it with good luck and checking the defined types within the playground..

updatePuppies->updatePuppiesPayload

It would be a great help if a section would be added to help, where the documentation only shows how to extend a current mutation, since al created contenttypes has Payload within their Schema

module.exports = {
  definition: ``,
    Mutations:{
       updatePuppiesPayload :{
         resolver:'puppies.update',
         policiy:['isOwner']
      }
    }
};

@Aurelsicoko
Copy link
Member

@merijnponzo I'm not sure to understand but you weren't able to override the default generate mutation updatePuppies and you had to create another one updatePuppiesPayload to make it work?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
issue: bug Issue reporting a bug severity: medium If it breaks the basic use of the product but can be worked around
Projects
None yet
Development

No branches or pull requests

7 participants