GraphQL - Unknown directive "unique" - graphql

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

Related

GraphQL Relay introspection query fails: Unknown field '__type' on type 'Query'

I have a React application with a GraphQL client (Relay).
I need to make an introspection query to get all the types of a certain enum.
This is my query:
import { graphql } from 'react-relay'
export const corporationTypeEnumQuery = graphql`
query corporationTypeEnumQuery {
__type(name: "CorporationTypeEnum") {
enumValues {
name
}
}
}
`
When I try to compile the app, Relay throws the following error:
Unknown field '__type' on type 'Query'
When I try the exact same query on GraphIQL (the playground that the server offers me), there is no error, and the query is successful.
Please tell me what could be wrong with my GraphQL query. Any suggestions are well received.
The __type must be part of your schema. Graphql spec by default said this should be hidden and not part of schema.. You need to extend your server to expose it or manually put them to schema..
Server can handle that but compiler not since it require explicit definition in .graphql

Strapi: Is there a to override plugin GraphQL schema?

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?

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.

AWS-Amplify API module: how to make GraphQL fields unique?

AWS-Amplify provides a couple of directives to build an GraphQL-API. But I haven't found out how to ensure uniqueness for fields.
I want to do something like in GraphCool:
type Tag #model #searchable {
id: ID!
label: String! #isUnique
}
This is an AWS-Amplify specific question. It's not about how to do this with generic GraphQL. It's very specifically about how to do this with AWS-Amplify's API module. (https://aws-amplify.github.io/docs/js/api)
Hey thanks for the question. This is not yet possible by default using the amplify-cli but you could do this yourself using pipeline resolvers and an extra index on your DynamoDB table. The steps to do this are as follows:
Create a GSI on the table where the label is the HASH KEY.
Create a pipeline resolver on the Mutation.createTag field in your schema. You can turn off the auto-generated Mutation.createTag mutation by changing your #model definition to #model(mutations: { update: "updateTag", delete: "deleteTag" }).
Create a function named LookupLabel that issues a Query against the new GSI where the label = $ctx.args.input.label. If this returns a value, throw an error with $util.error("Label is not unique"). If it returns no values then continue.
Create a function named CreateTag that issues a PutItem against the Tag table.
Add those two functions in order to your pipeline resolver.
You can read more about pipeline resolvers here https://docs.aws.amazon.com/appsync/latest/devguide/pipeline-resolvers.html.
As of writing amplify does not yet support custom & pipeline resolvers but you can read more about the feature here https://github.com/aws-amplify/amplify-cli/issues/574 as it will be supported in the future. For now you can add the resolver manually in the AWS AppSync console or via your own CloudFormation template that targets the id of the API created by Amplify. It would also be helpful if you create an issue here (https://github.com/aws-amplify/amplify-cli/issues) and tag this as a feature request because it would be possible to automate this with an #unique directive but this would need to be planned.
Thanks
Update: now you can use #primarykey and #index annotations:
https://docs.amplify.aws/cli/migration/transformer-migration/#what-is-changing
basic:
profile #model {
name
email #primaryKey - has to be unique
other
}
so if you needed something like:
profile #model {
name
email: String! #hasOne
other
}
email #model {
email: String! #primaryKey
}
if you are on an older version see below
I will eventually be testing this out to see if this works but you might be able to do something like rename the id to a string!
so...
type Tag #model #key["id"] {
id: String!
}
or:
type Customer #model #key(fields: ["email"]) {
email: String!
username: String
}
this second one is taken directly from the docs: https://docs.amplify.aws/cli/graphql-transformer/key#designing-data-models-using-key
The docs were updated recently so hopefully they are easier for everyone to understand.
If you need a more advanced workflow with allot of keys, and stuff like that then you just have to separate things out and make more types for example:
type Customer #model {
id: String!
email: Email! #hasOne
username: String
}
type email #model #key(fields: ["email"]) {
email: String!
}

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.

Resources