Is it possible to have schema directives for input parameters? - javascript

I have already created a hasRole directive. I only want to include certain input parameters if the user has the admin role:
const typeDefs = gql`
type Article {
id: ID!
title: String!
content: String!
sponsor: String
}
input CreateArticleInput {
title: String!
content: String!
sponsor: String // include if #hasRole(role: "admin")
type Mutation {
createArticle(input: CreateArticleInput!): Article!
publishArticle(articleId: ID!): Boolean! #hasRole(role: "editor")
}
`
The goal is to provide the sponsor input parameter optionally if the user has the role "admin", otherwise, do not let the user include a "sponsor". I wonder if the native #include or #skip directives can be used in tandem with my custom #hasRole directive to achieve this? ..just a thought.
Is something like this possible? I am not even sure if this is allowed in the input type.

Related

How to group GraphQL query objects into namespaces?

How can I group my queries into namespaces in GraphQL? I have something like this right now:
const queryType = new g.GraphQLObjectType({
name: "Query",
fields: fields,
});
and in fields I have field -> object mappings and it works fine, but I'd like to group these mappings into two groups (live and historical). If I modify the above code to this however:
const queryType = new g.GraphQLObjectType({
name: "Query",
fields: {
historical: {
type: new g.GraphQLObjectType({
name: "historical",
fields: fields,
})
}
},
});
everything resolves to null. How can I write a resolver for this grouping? Is it possible at all?
so often people want namespaces for the sake of splitting up code, not sure if this is your end goal but you could achieve that this way aswell:
# in one file
type Mutation {
login(username: String, password: String): User
}
# in other file
extend type Mutation {
postX(title: String, message: String): X
}

Prisma: how to exclude properties from generated types

EDIT
there's a hidden danger in hiding fields in the TS definitions: the fields will not be accessible during development with intellisense, but the full object with "hidden" fields can be accidentally sent in a response, potentially exposing sensitive data.
I'm building my app using Prisma to connect to the DB (Next.js app). I'm having some trouble with the auto generated Typescript definitions.
I'm following the docs but I can't figure out how to select a subset of fields from Post. In their example:
import { Prisma } from '#prisma/client'
const userWithPosts = Prisma.validator<Prisma.UserArgs>()({
include: { posts: true }, // -> how can I exclude some fields from the Post type?
})
type UserWithPosts = Prisma.UserGetPayload<typeof userWithPosts>
Imagine Post being as follows (simplified):
model Post {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
title String
published Boolean #default(false)
author User #relation(fields: [authorId], references: [id])
authorId Int
}
I'd like to exclude some of the auto-generated fields from the Post type, for example createdAt. Basically user.posts[0] type will have all the fields except createdAt.
One solution could be:
const postData = Prisma.validator<Prisma.PostArgs>()({
select: { id: true, title: true, published: true, authorId: true }
})
type UserWithPosts = Omit<Prisma.UserGetPayload<typeof userWithPosts>, 'posts'> & {
posts: postData[]
}
But I was hoping for something a bit cleaner. Any alternatives?
I found a solution: instead of using include use select with a nested select for posts. The problem is that it becomes quite verbose and cumbersome to maintain (every time a field is added on the schema it must be added here as well...)
const userWithPosts = Prisma.validator<Prisma.UserArgs>()({
select: {
email: true,
name: true,
posts: {
select: {
id: true,
title: true,
published: true,
authorId: true
}
}
}
})

GraphQL throwing syntax errors

I am developing the GraphQL Node tutorial, and am up to step 7.
https://www.howtographql.com/graphql-js/7-subscriptions/
I am getting a number of syntax errors from this code in my datamodel.prisma file:
directive #id on FIELD_DEFINITION
directive #unique on FIELD_DEFINITION
directive #createdAt on FIELD_DEFINITION
scalar DateTime
type Link {
id: ID! #id
createdAt: DateTime! #createdAt
description: String!
url: String!
postedBy: User
votes: [Vote!]!
}
type User {
id: ID! #id
name: String!
email: String! #unique
password: String!
links: [Link!]!
votes: [Vote!]!
}
type Vote {
id: ID! #id
link: Link!
user: User!
}
But am still getting 'User' type [#6:1] tried to redefine existing 'User' type [#15:5] and 'Link' type [#24:1] tried to redefine existing 'Link' type [#6:5].
I am also not sure if I am declaring directives or scalars correctly as this is missing from the official tutorial.
Can anyone give any advice on how to sort these issues?
Schema.graphql:
type Query {
info: String!
feed(filter: String, skip: Int, first: Int, orderBy: LinkOrderByInput): Feed!
}
type Feed {
links: [Link!]!
count: Int!
}
type AuthPayload {
token: String
user: User
}
type User {
id: ID!
name: String!
email: String!
links: [Link!]!
}
type Vote {
id: ID!
link: Link!
user: User!
}
type Link {
id: ID!
description: String!
url: String!
postedBy: User
votes: [Vote!]!
}
type Subscription {
newLink: Link
newVote: Vote
}
type Mutation {
post(url: String!, description: String!): Link!
signup(email: String!, password: String!, name: String!): AuthPayload
login(email: String!, password: String!): AuthPayload
vote(linkId: ID!): Vote
}
enum LinkOrderByInput {
description_ASC
description_DESC
url_ASC
url_DESC
createdAt_ASC
createdAt_DESC
}
I had the same error this morning and I have a feeling it has something to do with caching. It went away when I renamed the variable. In your case, change all 'Link' definition/references to 'LinkTwo' and see if the error goes away. Same with 'User'... change it to 'UserTwo'. If it does, perhaps you can rename them back afterwards.
I haven't used Prisma before and only glanced at the tutorial but it looks like you're defining two User types; you have one in datamodel.prisma and Schema.graphql (I couldn't find two definitions of User in the tutorial). If they are read into the same instance, that'll be the reason why graphql thinks you are trying to redefine the User type. Remove one or, if it's applicable, change the second to extend type User should solve the syntax error.

How can a graphql mutation accept an array of arguments with apollo server express?

I'm creating a shopping cart in my frontend, and I want to pass all the items in the shopping cart as an array to my mutation addLicense on my backend, so I don't have to make multiple API calls. Is this possible? If so, how, or what are my options?
I've tried to add square brackets around the arguments like this
extend type Mutation {
addLicense([
licenseType: String!
licenseAmount: String!
isActive: Boolean
expirationDate: Date!
]): License!
}
I've also tried to set the object type as an argument
extend type Mutation {
addLicense(
license: [License]
): License!
First attempt throws this error
/app/node_modules/graphql/language/parser.js:1463
throw (0, _error.syntaxError)(lexer.source, token.start, "Expected ".concat(kind, ", found ").concat((0, _lexer.getTokenDesc)(token)));
^
GraphQLError: Syntax Error: Expected Name, found [
at syntaxError
(/app/node_modules/graphql/error/syntaxError.js:24:10)
The other attempt throws this error
Error: The type of Mutation.addLicense(license:) must be Input Type but got: [License].
your mutation:
type Mutation {
"""
Add multiple items to basket
"""
addLicenses(licenses: [License!]!): LicenseMutationBatchResult
}
your interface input:
input License {
licenseType: String!
licenseAmount: String!
isActive: Boolean
expirationDate: Date!
}
whatever you give back:
type LicenseMutationBatchResult {
...whatever you give back here...
}
I got some advices over at the GraphQL Slack. I solved it by adding a new Input Type.
input LicenseInput {
id: ID
licenseType: String!
licenseAmount: String!
isActive: Boolean
expirationDate: Date
course: String!
organizationID: String!
price: Int!
}
I was then able to add my mutation like so
extend type Mutation {
addLicense(
license: [LicenseInput] <-
): License!
}

Mongoose find returns different to client find [duplicate]

I am trying to validate and save a Passport profile with this structure:
http://passportjs.org/guide/profile/
This is the scheme I came up with:
// Define the schema.
schema = new mongoose.Schema({
// The name of this user, suitable for display.
displayName: String,
// Each e-mail address ...
emails: [{
// ... with the actual email address ...
value: String,
// ... and the type of email address (home, work, etc.).
type: String
}],
// A unique identifier for the user, as generated by the service provider.
id: String,
// The name ...
name: {
// ... with the family name of this user, or "last name" in most Western languages ...
familyName: String,
// ... with the given name of this user, or "first name" in most Western languages ...
givenName: String,
// ... and with the middle name of this user.
middleName: String
},
// The provider which with the user authenticated.
provider: String
});
The e-mail has a property called 'type', which is reserved for a mongoose type. How do I solve this?
You need to define the field using an object:
type: {type: String}
Update for Mongoose 4+
You have to define the typeKey to the schema.
const schema = new Schema({
//Define a field called type of type String
type: { $type: String },
//Define a field called whatever of type Array
whatever: { $type: Array }
}, { typeKey: '$type' });
So all the schema will use the keyword $type to set the type of the field. And you can safely use type to set the name of the field.
https://mongoosejs.com/docs/guide.html#typeKey

Categories