This is the error am getting
node_modules\apollo-server-core\dist\ApolloServer.js:358
throw Error('Apollo Server requires either an existing schema, modules or typeDefs');
Here is my code:
users.typeDefs.js
On top I have "import { gql } from "apollo-server";
export default gql `"
type User {
id: String!
firstName: String!
lastName: String
username: String!
email: String!
createdAt: String!
updatedAt: String!
}
type Mutation {
createAccount(
firstName: String!
lastName: String
username: String!
email: String!
password: String!
): User
}
type Query {
seeProfile(username:String): User
}
`;
Here is my users.mutations.js
On top I have:
import { PrismaClient } from "#prisma/client";
import client from "../client";"
Here is the main code:
export default {
Mutation: {
createAccount: async (
_, {
firstName,
lastName,
username,
email,
password
}
) => {
//check if username or email are already on DB.
const existingUser = await client.user.findFirst({
where: {
OR: [
{
username,
},
{
email,
}
],
},
});
console.log(existingUser);
// hash password
// save and return the user
},
} ,
};
The users.queries.js is export default,
Here is my schema.js and client.js
import { mergeTypeDefs, mergeResolvers, } from "#graphql-tools/merge";
import { loadFilesSync } from "#graphql-tools/load-files";
import { makeExecutableSchema } from "#graphql-tools/schema";
const loadedTypes = loadFilesSync(`${__dirname}/**/*.typeDefs.js`);
const loadedResolvers = loadFilesSync(`${__dirname}/**/*.{queries,mutations}.js`);
const typeDefs = mergeTypeDefs(loadedTypes);
const resolvers = mergeResolvers(loadedResolvers);
const schema = makeExecutableSchema({typeDefs, resolvers});
export default schema;
import { PrismaClient } from "#prisma/client";
const client = new PrismaClient ();
export default client;
Here is also my server.js
require ("dotenv").config();
import { ApolloServer, gql } from "apollo-server";
import {schema} from "./schema";
const server = new ApolloServer({
schema,
});
const PORT = process.env.PORT
server.listen(PORT).then(() => {
console.log(`🚀 Server ready at http://localhost:${PORT} ✅ `);
});
Related
I am trying to Prisma along side with Apollo Server
and I keep getting this error
GraphQLError: Syntax Error: Expected Name, found ":"
this is the index.ts file
import { PrismaClient } from '#prisma/client';
import { ApolloServer } from 'apollo-server';
import { typeDefs } from './schema/schema';
import { Query } from './resolvers/Query';
import { Mutation } from './resolvers/Mutation';
const prisma = new PrismaClient();
const server = new ApolloServer({
typeDefs,
resolvers: {
Query,
Mutation,
},
context: {
prisma,
},
});
server.listen().then(({ url }: any) => {
console.log(`Server is running on ${url}`);
});
this is the schema.ts file
const { gql } = require('apollo-server');
export const typeDefs = gql`
type Query {
getProducts: [Product!]!
}
type Mutation {
addProduct(input: addProductInput): Boolean!
}
type Product {
name: String!
price: Float!
description: : String!
}
input addProductInput {
name: String!
price: Float!
description: : String!
}
`;
this is the Query.ts file in the resolvers folder
export const Query = {
getProducts: async (parent: any, args: any, { prisma }: any) => {
return await prisma.products.findMany();
},
};
this is the Query.ts file in the resolvers folder
export const Mutation = {
addProduct: async (parent: any, { input }: any, { prisma }: any) => {
const productData = {
name: input.name,
price: input.price,
description: input.description,
};
await prisma.products.create({
data: productData,
});
return true;
},
};
and lastly this is the Product model in schema.prisma file
model Product {
##map(name: "products")
id Int #id #default(autoincrement())
name String
price Float
description String
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
I have done some researches and all I got is that might be a missing bracket or a curly bracket, but I reviewed my code multiple times and did not find any mistakes.
In the schema definition, pay close attention to the Product type and addProductInput:
type Product {
name: String!
price: Float!
description: : String!
}
input addProductInput {
name: String!
price: Float!
description: : String!
}
`;
Are you sure the description fields should have two colons? I think they shouldn't have the middle one, and just be like description: String!
I'm sitting for 2 days trying to get my setup right. My target is Next.js with ApolloGraphQl for Database request as well as local state management handling.
My problem is the setup for the local state management. Don't know why i'm unable to correctly get it to work. I hope you can help me out.
I pushed my actual status of the project on github using the following repo:
https://github.com/Maetes/apollo-next-local
UPDATE:
it is fine to query and mutate the state when i just call the cache object itself so all is fine. But when i try to trigger a resolver, nothing happens. I'ts like the Apollo-client does not see the typedefs and resolvers.
Here is my useApollo Hook with Client init:
import { IncomingMessage, ServerResponse } from 'http';
import { useMemo } from 'react';
import { ApolloClient } from 'apollo-client';
import { InMemoryCache, NormalizedCacheObject } from 'apollo-cache-inmemory';
import { resolvers } from './localResolvers';
import { typeDefs } from './localTypeDefs';
import {
CREATE_USER,
GET_CURRENT_USER,
SET_CURRENT_USER,
ALL_USERS,
} from './localDocuments';
let apolloClient: ApolloClient<NormalizedCacheObject> | undefined;
export type ResolverContext = {
req?: IncomingMessage;
res?: ServerResponse;
};
function createIsomorphLink(context: ResolverContext = {}) {
if (typeof window === 'undefined') {
const { SchemaLink } = require('apollo-link-schema');
const { schema } = require('../pages/api/index');
return new SchemaLink({ schema, context });
} else {
const { HttpLink } = require('apollo-link-http');
return new HttpLink({
uri: 'http://localhost:3000/api',
credentials: 'same-origin',
});
}
}
function createApolloClient(context?: ResolverContext) {
let cache = new InMemoryCache();
cache.writeData({
data: {
currentUser: {
__typename: 'CurrentUser',
email: '',
nachname: '',
title: '',
id: '',
},
},
});
let client = new ApolloClient({
ssrMode: typeof window === 'undefined',
link: createIsomorphLink(context),
cache: cache,
typeDefs,
resolvers,
});
// client.writeData({
// data: {
// currentUser: {
// __typename: 'CurrentUser',
// email: '',
// nachname: '',
// title: '',
// id: '',
// },
// },
// });
return client;
}
export function initializeApollo(
initialState: any = null,
// Pages with Next.js data fetching methods, like `getStaticProps`, can send
// a custom context which will be used by `SchemaLink` to server render pages
context?: ResolverContext
) {
const _apolloClient = apolloClient ?? createApolloClient(context);
// If your page has Next.js data fetching methods that use Apollo Client, the initial state
// get hydrated here
if (initialState) {
_apolloClient.cache.restore(initialState);
}
// For SSG and SSR always create a new Apollo Client
if (typeof window === 'undefined') return _apolloClient;
// Create the Apollo Client once in the client
if (!apolloClient) apolloClient = _apolloClient;
return _apolloClient;
}
export function useApollo(initialState: any) {
const store = useMemo(() => initializeApollo(initialState), [initialState]);
return store;
}
This is my typedef file:
import gql from 'graphql-tag';
export const typeDefs = gql`
extend type Query {
getCurrentUser: CurrentUser!
}
type CurrentUser {
email: String!
nachname: String!
title: String!
id: ID!
__typename: String!
}
extend type Mutation {
setCurrentUser(
email: String!
nachname: String!
title: String!
id: ID!
): CurrentUser!
}
`;
this are my resolvers:
import { InMemoryCache } from 'apollo-cache-inmemory';
import { GET_CURRENT_USER } from './localDocuments';
export const resolvers = {
CurrentUser: {
currentUser: (_: {}, { cache }: { cache: InMemoryCache }) => {
console.log('Resolver Query triggered');
// const { user }: any = cache.readQuery({
// query: GET_CURRENT_USER,
// });
const data: any = {};
data.__typename = 'CurrentUser';
return data;
},
getCurrentUser: (_: {}, { cache }: { cache: InMemoryCache }) => {
console.log('Resolver Query triggered');
// const { user }: any = cache.readQuery({
// query: GET_CURRENT_USER,
// });
const data: any = {};
data.__typename = 'CurrentUser';
return data;
},
},
Query: {
getCurrentUser: (_: {}, { cache }: { cache: InMemoryCache }) => {
console.log('Resolver Query triggered');
// const { user }: any = cache.readQuery({
// query: GET_CURRENT_USER,
// });
const data: any = {};
data.__typename = 'CurrentUser';
return data;
},
currentUser: (_: {}, { cache }: { cache: InMemoryCache }) => {
console.log('Resolver Query triggered');
// const { user }: any = cache.readQuery({
// query: GET_CURRENT_USER,
// });
const data: any = {};
data.__typename = 'CurrentUser';
return data;
},
},
Mutation: {
setCurrentUser: (
_: {},
variables: any,
{ cache }: { cache: InMemoryCache }
) => {
const { currentUser }: any = cache.readQuery({ query: GET_CURRENT_USER });
console.log('mutationResolver Triggered');
console.log(
'olduser',
currentUser.email,
currentUser.nachname,
currentUser.title
);
const newUser = {
email: variables.email,
title: variables.title,
nachname: variables.nachname,
__typename: 'CurrentUser',
};
console.log('newUser', newUser);
const erg = cache.writeQuery({
query: GET_CURRENT_USER,
data: newUser,
});
return newUser;
},
},
};
And finaly my Document file for individual input. Please note in the GetCurrentUserQuery query when i change "getCurrentUser" to "currentUser" all is working fine cause apollo targets the raw object itself.
import gql from 'graphql-tag';
//Server
export const ALL_USERS = gql`
query allUsersQuery {
allUsers {
title
nachname
email
id
__typename
}
}
`;
//client
export const GET_CURRENT_USER = gql`
query GetCurrentUserQuery {
getCurrentUser #client(always: true) {
email
nachname
title
__typename
}
}
`;
//Client
export const SET_CURRENT_USER = gql`
mutation SetCurrentUserMutation(
$email: String!
$nachname: String!
$title: String!
$id: String!
) {
setCurrentUser(email: $email, nachname: $nachname, title: $title) #client {
email
title
nachname
id
__typename
}
}
`;
//Server
export const CREATE_USER = gql`
mutation CreateUserMutation(
$email: String!
$nachname: String!
$title: String!
$password: String!
) {
createUser(
email: $email
nachname: $nachname
title: $title
password: $password
) {
__typename
email
nachname
title
password
id
}
}
`;
Hello I need to check if there is an email in the database already:
with this:
return User.findOne({ where: { email } }).then((user) => {
if (user) return false;
return true;
});
I have the following inputtypes:
#InputType()
export class RegisterInput {
#Field()
#IsEmail({}, { message: 'Invalid email' })
email: string;
#Field()
#Length(1, 255)
name: string;
#Field()
password: string;
}
I would like to know if there is any way for me to validate the email in the inputtype? or just in my resolve:
#Mutation(() => User)
async register(
#Arg('data')
{ email, name, password }: RegisterInput,
): Promise<User> {
const hashedPassword = await bcrypt.hash(password, 12);
const user = await User.create({
email,
name,
password: hashedPassword,
}).save();
return user;
}
Actually you can register your own decorator for class-validator
For example it can look something like this:
isEmailAlreadyExists.ts
import {
registerDecorator,
ValidationOptions,
ValidatorConstraint,
ValidatorConstraintInterface,
} from 'class-validator';
import { UserRepo } from '../../repositories/UserRepo';
import { InjectRepository } from 'typeorm-typedi-extensions';
#ValidatorConstraint({ async: true })
export class isEmailAlreadyExist
implements ValidatorConstraintInterface {
#InjectRepository()
private readonly userRepo: UserRepo;
async validate(email: string) {
const user = await this.userRepo.findOne({ where: { email } });
if (user) return false;
return true;
}
}
export function IsEmailAlreadyExist(validationOptions?: ValidationOptions) {
return function (object: Object, propertyName: string) {
registerDecorator({
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
constraints: [],
validator: isEmailAlreadyExist,
});
};
}
If you're injecting dependencies than you should in inject it in class-validator too. Simply add to your main file this:
import { Container } from 'typedi';
import * as classValidator from 'class-validator';
classValidator.useContainer(Container);
...
const schema = await buildSchema({
resolvers: [...],
container: Container,
});
Then you can use decorator in your InputType
import { InputType, Field } from 'type-graphql';
import { IsEmailAlreadyExist } from '../../../utils/validators/isEmailAlreadyExist';
#InputType()
export class YourInput {
#Field()
#IsEmailAlreadyExist()
email: string;
}
I actually just figured this out myself for my own project.
You can simply add a validation on the email from RegisterInput argument and throw an error if the email already exists.
import { Repository } from 'typeorm'
import { InjectRepository } from 'typeorm-typedi-extensions'
...
// Use dependency injection in the resolver's constructor
constructor(
#InjectRepository(User) private readonly userRepository: Repository<User>
) {}
...
// Your mutation
#Mutation(() => User)
async register(
#Arg('data')
{ email, name, password }: RegisterInput,
): Promise<User> {
const hashedPassword = await bcrypt.hash(password, 12);
const userWithEmail = this.userRepository.find({ email: email })
// If a user with the email was found
if (userWithEmail) {
throw new Error('A user with that email already exists!')
}
const user = await User.create({
email,
name,
password: hashedPassword,
}).save();
return user;
}
To use the InjectRepository make sure you add a "container" to your buildSchema function:
import { Container } from 'typedi'
...
const schema = await buildSchema({
resolvers: [...],
container: Container
})
Let me know if this works out for you? Thanks!
I'm trying to provide a mock schema to a component using React Apollo 2.1. However, it returns this error.
Error: Network error: No more mocked responses for the query: {
me {
id
email
username
first_name
last_name
bio
website
}
}
, variables: {}
at new ApolloError (ApolloError.js:43)
at ObservableQuery.currentResult (ObservableQuery.js:107)
at Query._this.getQueryResult (react-apollo.browser.umd.js:319)
at Query.render (react-apollo.browser.umd.js:421)
at finishClassComponent (react-dom.development.js:8389)
at updateClassComponent (react-dom.development.js:8357)
at beginWork (react-dom.development.js:8982)
at performUnitOfWork (react-dom.development.js:11814)
at workLoop (react-dom.development.js:11843)
at renderRoot (react-dom.development.js:11874)
How did you add mock functionality on React Apollo 2.1? I tried searching the solutions but both information for older versions and newer ones and couldn't resolve this.
Here's the code.
index.stories.js
import React from 'react';
import { storiesOf } from '#storybook/react';
import { action } from '#storybook/addon-actions';
import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';
import gql from 'graphql-tag'
import { MemoryRouter } from 'react-router';
import { MockedProvider } from 'react-apollo/test-utils';
import { buildMockedClient } from '../../../mockedApolloClient';
import AccountSettings from './index';
const typeDefs = `
interface User {
id: ID!,
email: String!,
username: String,
first_name: String,
last_name: String,
bio: String,
website: String
}
type Student implements User {
id: ID!,
email: String!,
username: String,
first_name: String,
last_name: String,
bio: String,
website: String
}
type InputError {
key: String!
message: String!
}
type UserResult {
errors: InputError,
user: User
}
input UpdateAccountInput {
first_name: String
last_name:String
email: String
username: String
bio: String
website: String
}
type Query {
me: User
}
type Mutation {
updateAccount(params: UpdateAccountInput!): UserResult!
}
`
const typeResolvers = {
User: {
__resolveType(data) {
return data.__typename // typename property must be set by your mock functions
}
}
}
const me = {
id: () => 1,
email: () => 'testuser#test.jp',
username: () => 'hiro1107',
first_name: () => 'Atsuhiro',
last_name: () => 'Teshima',
bio: () => 'test',
website: () => 'https://www.test.jp',
}
const schema = makeExecutableSchema({
typeDefs,
typeResolvers
})
const mocks = {
User: () => ({
id: () => 1,
email: () => 'testuser#codegrit.jp',
username: () => 'hiro1107',
first_name: () => 'Atsuhiro',
last_name: () => 'Teshima',
bio: () => 'test',
website: () => 'https://www.codegrit.jp',
__typename: () => 'Student'
}),
Query: () => ({
me: () => me
})
}
addMockFunctionsToSchema({
schema,
mocks,
preserveResolvers: false
});
storiesOf('Account Settings', module)
.addDecorator(story => (
<MockedProvider client={mockedClient} mocks={mocks} >
<MemoryRouter initialEntries={['/']}>{story()}</MemoryRouter>
</MockedProvider>
))
.add('With Mock', () => (
<AccountSettings />
));
const mockedClient = buildMockedClient(schema);
storiesOf('Account Settings', module)
.addDecorator(story => (
<MockedProvider client={mockedClient} mocks={mocks} >
<MemoryRouter initialEntries={['/']}>{story()}</MemoryRouter>
</MockedProvider>
))
.add('With Mock', () => (
<AccountSettings />
));
mockedApolloClient.js
import { ApolloClient } from 'apollo-client';
import { SchemaLink } from 'apollo-link-schema';
import { InMemoryCache } from 'apollo-cache-inmemory';
const apolloCache = new InMemoryCache(window.__APOLLO_STATE__);
export function buildMockedClient(schema) {
return new ApolloClient({
cache: apolloCache,
link: new SchemaLink({ schema })
})
}
package.json
"apollo-cache-inmemory": "^1.1.9",
"apollo-client": "^2.2.5",
"apollo-link-context": "^1.0.7",
"apollo-link-http": "^1.5.2",
"apollo-link-schema": "^1.1.0",
"graphql": "^0.13.1",
"graphql-tag": "^2.8.0",
"graphql-tools": "^2.24.0",
"react": "^16.3.1",
"react-apollo": "^2.1.0",
"react-dom": "^16.3.1",
I found out that I need to use ApolloProvider instead MockedProvider.
So, this code will work.
import React from 'react';
import { storiesOf } from '#storybook/react';
import { action } from '#storybook/addon-actions';
import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';
import gql from 'graphql-tag'
import { MemoryRouter } from 'react-router';
import { ApolloProvider, Query } from 'react-apollo';
import { buildMockedClient } from '../../../mockedApolloClient';
import AccountSettings from './index';
const typeDefs = `
type Query {
me: User!
}
type Mutation {
updateAccount(params: UpdateAccountInput!): UserResult!
}
interface User {
id: ID!,
email: String!,
username: String,
first_name: String,
last_name: String,
bio: String,
website: String
}
type Student implements User {
id: ID!,
email: String!,
username: String,
first_name: String,
last_name: String,
bio: String,
website: String
}
type InputError {
key: String!
message: String!
}
type UserResult {
errors: InputError,
user: User
}
input UpdateAccountInput {
first_name: String
last_name:String
email: String
username: String
bio: String
website: String
}
`
const typeResolvers = {
User: {
__resolveType(data) {
return data.__typename()
}
}
}
const mocks = {
User: () => ({
id: () => 1,
email: 'testuser#codegrit.jp',
username: 'hiro1107',
first_name: 'Atsuhiro',
last_name: 'Teshima',
bio: 'test',
website: 'https://www.test.jp',
__typename: 'Student',
}),
Student: () => ({
id: () => 1,
email: 'testuser#test.jp',
username: 'hiro1107',
first_name: 'Atsuhiro',
last_name: 'Teshima',
bio: 'test',
website: 'https://www.test.jp',
__typename: () => 'Student'
}),
query: () => ({
me: () => ({
id: () => 1,
email: 'testuser#test.jp',
username: 'hiro1107',
first_name: 'Atsuhiro',
last_name: 'Teshima',
bio: 'test',
website: 'https://www.test.jp',
__typename: () => 'Student'
})
})
}
const schema = makeExecutableSchema({
typeDefs,
resolvers: typeResolvers
})
addMockFunctionsToSchema({
schema,
mocks,
preserveResolvers: true
});
const client = buildMockedClient(schema);
const userQuery = gql`
query {
me {
id
email
username
first_name
last_name
bio
website
}
}
`
storiesOf('Account Settings', module)
.addDecorator(story => (
<ApolloProvider client={client} >
<MemoryRouter initialEntries={['/']}>{story()}</MemoryRouter>
</ApolloProvider>
))
.add('With Mock', () => (
<AccountSettings />
));
Im trying to return a string with React and GraphQL but I'm getting stuck at the first stage. Here is my attempt:
import { makeExecutableSchema } from 'graphql-tools';
const typeDefs = `
type Query {
author: Person
}
type Person {
name: String
}
`;
const resolvers = {
Query: {
author: { name: 'billy' },
},
};
const schema = makeExecutableSchema({
typeDefs,
resolvers,
});
createApolloServer({ schema });
And this is my understanding of that code:
In my schema I've defined a Query called author which should return a Person.
A Person has a name field which is a string.
My resolver has a Query called author which should return an object with a name field of value 'billy'
However in my Graphicool browser tools this query:
query {
author{
name
}
}
Returns this:
{
"data": {
"author": null
}
}
Resolvers are functions which GraphQL will call when resolving that particular field. That means your resolvers object should look more like this:
const resolvers = {
Query: {
author: () => ({ name: 'billy' }),
},
}
Or, alternatively,
const resolvers = {
Query: {
author() {
return { name: 'billy' }
},
},
}
You can check out the docs for more information.
import { createApolloServer } from 'meteor/apollo';
import { makeExecutableSchema } from 'graphql-tools';
import merge from 'lodash/merge'; // will be useful later when their are more schemas
import GroupsSchema from './Groups.graphql';
import GroupsResolvers from './resolvers';
const typeDefs = [GroupsSchema];
const resolvers = merge(GroupsResolvers);
const schema = makeExecutableSchema({
typeDefs,
resolvers,
});
createApolloServer({ schema });
In ./Groups.graphql:
type Query {
hi: String
groups: [Group]
group: Group
}
type Group {
name: String
}
In './resolvers':
export default {
Query: {
hi() {
return 'howdy';
},
groups() {
return [{ name: 'one', _id: '123' }, { name: 'two', _id: '456' }];
// return Groups.find().fetch();
},
group() {
return { name: 'found me' };
},
},
};
In a React component:
const mainQuery = gql`
{
groups {
name
}
}
`;
export default graphql(mainQuery)(ComponentName);