Strapi: Is there a to override plugin GraphQL schema? - graphql

I am trying to modify the GraphQL schema of the users-permissions plugin.
I want to change:
type UsersPermissionsLoginPayload {
jwt: String!
user: UsersPermissionsMe!
}
to:
type UsersPermissionsLoginPayload {
isAuthenticated: Boolean!
user: UsersPermissionsMe!
}
But I get many errors when I create ./extensions/users-permissions/config/schema.graphql.js:
...
There can be only one type named "UsersPermissionsLoginInput".
Field "UsersPermissionsLoginInput.identifier" can only be defined once.
Field "UsersPermissionsLoginInput.password" can only be defined once.
Field "UsersPermissionsLoginInput.provider" can only be defined once.
There can be only one type named "UsersPermissionsLoginPayload".
Field "UsersPermissionsLoginPayload.jwt" can only be defined once.
Field "UsersPermissionsLoginPayload.user" can only be defined once.
...
What is the correct way to customize/extend the schema?
Edit:
I see the types can simply be extended like so:
module.exports = {
definition: `
extend type UsersPermissionsLoginPayload {
isAuthenticated: Boolean!
}
`
}
that adds the isAuthenticated field to the UsersPermissionsLoginPayload type but does not remove the jwt field.
Is there no way to override the typedefs and resolvers? Do I need to implement my custom functionality using new types and new unique resolvers?

Related

GraphQL variable combination validation

Imagine the following (simplified) GraphQL schema:
type User {
username: String
email: String
}
type Query {
user(username: String, email: String): User
}
If I would only want to allow querying user by giving a username, I would of course change it to user(username: String!), making the username required using the exclamation mark. Same thing vice versa with the email.
Is it possible though to have a GraphQL native solution where I validate for the existence of only either one (logical XOR) or at least one (logical OR) of the two input parameters?
Of course I could do it in the query resolver manually, but a #constraint directive like it is being used in Apollo GraphQL spreading across variables would be nice.
Directly ... not possible:
check fields existence [within args] on resolver;
use #constraint to check each field shape;
Indirectly:
you can try to use union of input types:
.
type UserNameInput {
username: String!
}
type UserEmailInput {
email: String!
}
type UserInput = UserNameInput | UserEmailInput
type Query {
user(input: UserInput): User
}

Apollo client's codegen adds unwanted "or null" in my types

Apollo client's codegen adds | null in the generated types, and I don't understand why they are there and how to get rid of them.
I see no reason why the API would return an array of null, so I don't want to check in my code weather the oject is null or not everytime.
Offending generated types from apollo codegen:
export interface MusicGenres_musicGenres {
name: string;
}
export interface MusicGenres {
musicGenres: (MusicGenres_musicGenres | null)[];
^^^^^^
WHY ?
}
My Graphql Schema:
type Query {
musicGenres: [MusicGenre]!
}
type MusicGenre {
id: ID!
name: String!
}
Query in my TypeScript code from which are generated the types:
gql`
query MusicGenres {
musicGenres { name }
}
`
In your schema, you have the following field definition:
musicGenres: [MusicGenre]!
This means that while musicGenres will be a list and will itself never be null, any item in the list could be null. If you want to indicate that all items in the list are also non-nullable, your field definition should instead be:
musicGenres: [MusicGenre!]!
See this post for an extended explanation.

Omitting the field in response with GraphQL Apollo

I am using Apollo GraphQL server and directives.
Here is my simple schema. Notice the directive on the token field, User type.
const typeDefs = `
directive #allow(service: String) on FIELD_DEFINITION
type User {
email: String!
pass: String!
... other fields here
token: String #allow(service: "login")
}
type Mutation {
login(email: String!, pass: String!): User
}`;
I would like to return the token field only if the login has been called. Otherwise, I would like to return the User object without the token field, all I could find is throwing an Exception or returning the null in the "token" field.
class SkipDirective extends SchemaDirectiveVisitor {
visitFieldDefinition(field, details) {
const { resolve = defaultFieldResolver } = field;
field.resolve = async function (...args) {
// If called in context different from "login"
// Here I would like to just "delete" the "token" field
else {
const result = await resolve.apply(this, args);
return result;
}
};
}
}
Ideas?
If a field is requested, it should be returned with either a value matching the field's type or else null. To do otherwise would break the spec.
There is no way you can modify this behavior through a schema directive. A field definition directive can only change runtime behavior by modifying the field's resolver. However, by the time the resolver is called, the selection set has already been determined so it's too late to modify it. Returning null or throwing an error are pretty much the only two options.
You might be able to implement some kind of workaround through either the formatResponse option or a custom plugin. However, because this behavior would break the spec, there's no telling if it wouldn't cause issues with client libraries or other tools.

Change the exposed graphql schema through directives

Directives are nice to alter the behaviour of resolvers, but is there a way to directly change the exposed schema with them?
Example
expected superuser schema
type Query {
getBooks: [Book]
getAuthors: [Author]
}
expected normal user schema
type Query {
getBooks: [Book]
}
one definition to build them all
type Query {
getBooks: [Book] #allow(scopes: ["superuser"])
getAuthors: [Author]
}
The scope would be defined through the given context as i would build one schema for each possible scope.

GraphQL - Unknown directive "unique"

I just updated GraphQL from version 0.13.2 to 14.0.2. When starting the server, I get the error message: Error: Unknown directive "unique". This is my schema:
const { gql } = require('apollo-server')
// type Query is the root query
exports.typeDefs = gql`
type User {
username: String! #unique
password: String!
}
type Query {
getAllUsers: User
}
Note even though I'm using gql from apollo-server it's using GraphQL under the hood.
As you can see what is causing is the issue is that I've made it so the username has to be unique. The updated version of GraphQL must not have this directive anymore. Sure enough, removing #unique solves the issue. I still want username to be unique. I've read that you can create custom directives. How do I go about doing this?
I've encountered a similar scenario to yours when working in fully custom directives with the upgrade of graphql-tools to v14 the definition of the directive is needed within the schema. You can specify by field, object, mutation where your directive will work.
directive #requireAuth on FIELD_DEFINITION
To work in something like this, at field level
extend type Query {
me: String! #requireAuth
user(userId: ID!):User!
users: [User]!
}
And my class that extends SchemaDirectiveVisitor it's something like this
import { SchemaDirectiveVisitor } from "apollo-server";
export class YourCustomDirective extends SchemaDirectiveVisitor {
// Your code for the directive
}
In the link provided, there is the available methdos to use in order to have your custom logic at field, object, scalar, etc level. Hope this helps.
Schema Directive Visitor

Resources