Valid graphql schema not valid when using jest - graphql

I have a nestJs project that is using Graphql and Jest.
The thing is, the graphql schema generates correctly when running the app but not when using jest.
For this schema :
input LoginRequest {
email: String!
code: String!
}
type LoginResponse {
jwtToken: String!
refreshToken: String!
}
The app starts but using the jest command it returns :
Cannot determine a GraphQL output type for the "email". Make sure your class is decorated with an appropriate decorator.
jest.config.js is pretty generic :
module.exports = {
preset: 'ts-jest',
moduleFileExtensions: ['js', 'json', 'ts'],
rootDir: '.',
testEnvironment: 'node',
testMatch: ['**/*.spec.[jt]s?(x)'],
transform: {
'^.+\\.(t|j)s$': 'ts-jest',
},
testPathIgnorePatterns: [
'<rootDir>/build/',
'<rootDir>/dist',
'<rootDir>/node_modules',
],
}
I tried removing email in the schema so it looks like this :
input LoginRequest {
code: String!
}
type LoginResponse {
jwtToken: String!
refreshToken: String!
}
The app still starts with no issue but jest now returns :
Cannot determine a GraphQL output type for the "code". Make sure your class is decorated with an appropriate decorator.
And again for every fields until there's none left.
I found that I could use --runInBand or isolatedModules: true in the config but that does not fix the issue
Does Jest generate the graphql schema differently ? If so, where can I configure it correctly ?

Related

Querying all objects in Amplify mock api and getting null

I am using Amplify in a simple use case to mock an existing frontend. I have a cutdown schema.graphql as follows:
input AMPLIFY { globalAuthRule: AuthRule = { allow: public } }
schema {
query: Query
}
type Query {
getAirports: [Airport]
}
type Airport #model {
id: Int! #primaryKey
code: String!
city: String!
country: String!
}
The getAirports query is intended to return all the airports. I run amplify mock api and it generates all the resolvers.
When I navigate to http://localhost:20002, I can see the option to use getAirports, however it returns null even when data is present in the mocked database. The response is
{"data":null,"errors":[{"message":"Cannot return null for non-nullable field Query.getAirports.","locations":[{"line":2,"column":3}],"path":["getAirports"]}]}
I'm curious how I can write the schema to have a getAirports query in a way that it returns data a full list of Airports similar to listAirports which is created by default.

use mutation result in another mutation in graphql playground

I have 2 graphql mutations : mutation1 and mutation2.
mutation2 uses mutation1 result (field id).
I'd like to create a seed and then run it in graphql playground.
My issue is that i can't use the id field in mutationResult in my other mutation.
so - this line is an error : id: mutationResult.id
Is there a way to do this?
I know i can create a js script for this, or import apollo client, but i'd like to use gql seed file instead.
AND YES - i'm aware of this issue : https://github.com/graphql/graphql-js/issues/462
mutation {
mutationResult: mutation1(
params: {
email: "test#gmail.com"
name: "test"
}
) {
id
}
mutation2(
params: {
id: mutationResult.id // THIS IS AN ERROR
}
)
}

Should we add the backend graphql schema in the case of Apollo Client?

I'm using backend node server with the Apollo graphql (Server side) and on the client, I'm using Apollo Client as well.
I created a few client specific types in my client Schema for Apollo client but I'm wondering:
Should I do the same for backend Types (models)? Just to add some sanity, etc.
Let me explain it a bit detailed with an example:
Here is the client schema: (Client specific types)
import gql from 'graphql-tag';
export default gql`
type System {
showSignInModal: Boolean!
}
type Robot {
name: String!
status: String!
}
type Member {
name: String!
isLogged: Boolean!
}
type Author {
id: Int!
posts: Int!
name: String
}
input AuthorInput {
id: Int!
posts: Int!
name: String
}
`;
I have a query that fetches the user data from the server (Server specific data)
so should I describe the whole User type in my schema as well?
import gql from "graphql-tag";
export const GET_USER_SHORT_DATA = gql`
mutation getUserShortData {
me {
id,
email,
name,
profileUrl,
locale
}
}
`;
Thanks for any advice!
I assume you're using mongoose for your database operations. Your main types should be defined in your mongoose schema as GraphQL is just a query language meant for "getting only what you want". So, you should add the same types in both the places. In your mongoose code for database handling & In your GraphQL Schema for query fetch support.
For Client side, if you're using a typed language like typescript, then you should define them in the client side too so as to prevent bugs & get better IDE suggestions.

Custom schema, interface, #fileByRelativePath and gatsby-image

I'm trying to get an interface working with the new #fileByRelativePath resolver extension, to keep compatible with v3.
I'm using Prismic for my content, and gatsby-source-prismic v2. I have two content types in Prismic, and created the interface to be able to more easily query and map over both for a home page index.
Here's the functioning (but with deprecated inferred resolvers) schema:
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions
const typeDefs = `
interface indexPosts #nodeInterface {
id: ID!
uid: String!
data: Data!
type: String!
}
type Data {
title: Title!
date: Date!
featured: String!
featured_image: Featured_image!
body: Body!
}
type Title {
text: String!
}
type Featured_image {
localFile: File!
}
type Body {
html: String!
}
type PrismicGallery implements Node & indexPosts {
uid: String!
data: Data!
type: String!
}
type PrismicEssay implements Node & indexPosts {
uid: String!
data: Data!
type: String!
}
`
createTypes(typeDefs)
}
The problem comes after adding #fileByRelativePath to the Featured_image type definition. Doing so gives me an error during build:
"The "path" argument must be of type string. Received type undefined"
I'm unsure how to provide the necessary path argument, considering my images are third-party hosted. I'm trying to follow the brief guide at the end of this page and suspect the way to do it might be with a resolver or type builder and using 'source' to access the url field provided by both localFile and its parent, featured_image, but I can't figure it out!
I'm using gatsby-image and the childImageSharp convenience field to present the images, if that makes a difference at all!
I had exactly the same problem when I tried to use #fileByRelativePath. I managed to solve my problem by using #infer on the type that contained the File.
Try this:
type Featured_image #infer {
localFile: File!
}

Include relationship when querying node using Prisma generated wrapper

I am following the GraphQL Prisma Typescript example provided by Prisma and created a simple data model, generated the code for the Prisma client and resolvers, etc.
My data model includes the following nodes:
type User {
id: ID! #unique
displayName: String!
}
type SystemUserLogin {
id: ID! #unique
username: String! #unique
passwordEnvironmentVariable: String!
user: User!
}
I've seeded with a system user and user.
mutation {
systemUserLogin: createSystemUserLogin({
data: {
username: "SYSTEM",
passwordEnvironmentVariable: "SYSTEM_PASSWORD",
user: {
create: {
displayName: "System User"
}
}
}
})
}
I've created a sample mutation login:
login: async (_parent, { username, password }, ctx) => {
let user
const systemUser = await ctx.db.systemUserLogin({ username })
const valid = systemUser && systemUser.passwordEnvironmentVariable && process.env[systemUser.passwordEnvironmentVariable] &&(process.env[systemUser.passwordEnvironmentVariable] === password)
if (valid) {
user = systemUser.user // this is always undefined!
}
if (!valid || !user) {
throw new Error('Invalid Credentials')
}
const token = jwt.sign({ userId: user.id }, process.env.APP_SECRET)
return {
token,
user: ctx.db.user({ id: user.id }),
}
},
But no matter what I do, systemUser.user is ALWAYS undefined!
This makes sense - how would the client wrapper know how "deep" to recurse into the graph without me telling it?
But how can I tell it that I want to include the User relationship?
Edit: I tried the suggestion below to use prisma-client.
But none of my resolvers ever seem to get called...
export const SystemUserLogin: SystemUserLoginResolvers.Type<TypeMap> = {
id: parent => parent.id,
user: (parent, args, ctx: any) => {
console.log('resolving')
return ctx.db.systemUserLogin({id: parent.id}).user()
},
environmentVariable: parent => parent.environmentVariable,
systemUsername: parent => parent.systemUsername,
createdAt: parent => parent.createdAt,
updatedAt: parent => parent.updatedAt
};
And...
let identity: UserParent;
const systemUserLogins = await context.db.systemUserLogins({
where: {
systemUsername: user,
}
});
const systemUserLogin = (systemUserLogins) ? systemUserLogins[0] : null ;
if (systemUserLogin && systemUserLogin.environmentVariable && process.env[systemUserLogin.environmentVariable] && process.env[systemUserLogin.environmentVariable] === password) {
console.log('should login!')
identity = systemUserLogin.user; // still null
}
Edit 2: Here is the repository
https://github.com/jshin47/annotorious/tree/master/server
There are currently two ways to solve this problem:
Using the Prisma client as OP does at the moment
Using Prisma bindings as was suggested by #User97 in the accepted answer
You can learn more about the difference between Prisma client and Prisma bindings in this forum post.
As OP is currently using Prisma client, I'll use it for this answer as well!
Let's take a look at a statement OP made in the question:
This makes sense - how would the client wrapper know how "deep" to recurse into the graph without me telling it?
OP stated correctly that the Prisma client can't know how to deep to go into the graph and what relationships to fetch. In fact, unless explicitly told otherwise (e.g. using the $fragment API), the client will never fetch any relationships and will always only fetch the scalar values. From the Prisma docs:
Whenever a model is queried using the Prisma client, all scalar fields of that model are fetched. This is true no matter if a single object or a list of objects is queried.
So, how to properly resolve this situation? In fact, the solution is not to make changes to the way how the Prisma client is used, but to implement an additional GraphQL resolver function!
The point about resolvers is that they're fetching the data for specific fields in your schema. In OP's case, there currently is no resolver that would "resolve" the user relation that's defined on the SystemUserLogin type:
type SystemUserLogin {
id: ID! #unique
username: String! #unique
passwordEnvironmentVariable: String!
user: User! # GraphQL doesn't know how to resolve this
}
To resolve this situation, you need to implement a dedicated "type resolver" for it like so:
const resolvers = {
SystemUserLogin: {
user(parent, args, ctx) {
return ctx.db.systemUserLogin({id: parent.id}).user()
}
}
}
Full disclosure: I work at Prisma and we're working on adding better documentation and resources for that use case. Also check out this example where explicit resolvers for the author and posts relation fields are required for the same reason.
Hope that helps!
EDIT: We have also added a slightly more thorough explanation in the Prisma tutorial about Common resolver patterns.
Second parameter of prisma binding functions accept GraphQL query string. Changing following line from
const systemUser = await ctx.db.query.systemUserLogin({ username })
to
const systemUser = await ctx.db.query.systemUserLogin({ username }, `{id username user {id displayName}}`)
will give you the data of user.
Prisma binding will return only direct properties of model in case second parameter is not passed to it.

Resources