How can I make GraphQL support int8 type in Supabase? - graphql

I'm creating a simple CRUD app to learn GraphQL and am using a Supabase postgres instance. All queries and mutations work fine except for one thing, I can't get the id field from my schemas because they are of type int8 on Supabase, and GraphQL only supports Int.
I'm getting this error when I try to get a row's id using the gql Int type in my type defs: GraphQLError: Int cannot represent non-integer value: 1
I know the solution involves creating a custom scalar type as in this example, but I'm not sure how to implement this type. Also, I cannot change this on Supabase's side, so I must find a way to handle this in gql. How can I handle this type in GraphQL?
TypeDefs:
export const typeDefs = `#graphql
type User {
id: Int!
name: String!
email: String!
age: Int!
verified: Boolean!
}
type Todo {
id: Int!
title: String!
description: String!
}
type Query {
# users queries
getAllUsers: [User]
getUser(email: String!): User
# todo queries
getAllTodos: [Todo]
getTodo(id: String!): Todo
}
type Mutation {
createUser(name: String!, email: String!, age: Int!): User
createTodo(title: String!, description: String!): Todo
}
`;
Resolvers:
import { GraphQLScalarType } from 'graphql';
import { prisma } from '../lib/db.js';
const BigInt = new GraphQLScalarType({
// how do I implement this type?
});
export const resolvers = {
BigInt,
Query: {
getAllUsers() {
return prisma.user.findMany();
},
getUser(parent, args) {
return prisma.user.findUnique({
where: {
email: args.email,
},
});
},
getAllTodos() {
return prisma.todo.findMany();
},
getTodo(parent, args) {
return prisma.todo.findUnique({
where: {
id: args.id,
},
});
},
},
// parent, arge are other arguments that get passes to resolvers automatically
Mutation: {
createUser(parent, args) {
return prisma.user.create({
data: args,
});
},
createTodo(parent, args) {
return prisma.todo.create({
data: args,
});
},
},
};

Solved this by using the graphql-type-ints package. You can just install it and then add the type you need to your schemas and resolvers. However, I don't quite understand why we need to do this. If someone could explain why Supabase uses int8 and that doesn't conform to graphql's Int I would appreciate it.

Related

Cannot Get Apollo addItem Mutation to work on the client keep getting 400 error

All I want to do is add an item to the items array in my Cart object.
What I am trying to do is simply execute my backend addItem mutation. After that I want to manually update the cache, but for now I am just re-fetching the query because I am unable to even successfully get the query to run.
In this code I am using the pothos withinput plugin: link to docs
I have tried:
Just putting the hardcoded input object into the addItem hook
Listing each Variable out one by one into the addItem hook
Describing the types of each prop in the original gql MUTATION
And passing the hardcoded input into the addItem hook via variables object
Passing hardcoded values into the actual addItem mutation
I have tried inputting the proper typing via a gql tag example below:
const THE_TYPE = gql`input addItemInput {
cartId: String!
id: String!
name: String!
price: Float!
}
`
const MUTATION = gql`
mutation AddItem($input: ${THE_TYPE}!) {
addItem(input: $input){carts{
id
items{
name
}}}
`;
*When I run the following mutation in my graphiql interface it works:
mutation MyMutation{
addItem(input:{
cartId: "2",
id: "12",
name: "New Item!",
price: 1900,
}){
items{
name
}
}}
However when I run the mutation below I get a 400 error:
Error: Response not successful: Received status code 400
import { useQuery, gql, useMutation } from '#apollo/client';
export default function DisplayCarts() {
interface Cart {
id: string;
items: string[];
}
interface Items {
}
const GET_CARTS = gql`
query {
carts{
id
items{
name
}}} `;
const MUTATION = gql`
mutation AddItem($input: Any) {
addItem(input: $input){
carts{
id
items{
name
}}
}}`;
const { loading, error, data } = useQuery(GET_CARTS)
const [addItem] = useMutation(MUTATION, {
refetchQueries: [{ query: GET_CARTS }]
// update(cache, { data: { addItem } }) {
// addItem is the response of the query of add item function
// console.log(data);
// #ts-ignore
// const { carts } = cache.readQuery({ query: GET_CARTS });
// cache.writeQuery({
// query: GET_CARTS,
// data: { carts: [...carts, addItem] }
// })
// }
})
function AddTodo() {
let theInput = {
cartId: "2",
id: "12",
name: "New Item!",
price: 1900,
quantity: 2
}
// #ts-ignore
addItem({ variables: { input: theInput } });
};
Here is my backend resolver function using pothos
Keep in mind my query does work in my graphiql interface so the issue is probably not on the backend
builder.mutationType({
fields: (t) => ({
addItem: t.fieldWithInput({
input: {
cartId: t.input.string({ required: true }),
id: t.input.string({ required: true }),
name: t.input.string({ required: true }),
price: t.input.int({ required: true }),
quantity: t.input.int({ required: true, defaultValue: 1 }),
},
type: Cart,
resolve: (_, { input: { cartId, ...input } }) => {
const cart = CARTS.find((cart) => cart.id === cartId);
if (!cart) {
throw new Error(`Cart with id ${cartId} not found`)
}
return {
id: cartId,
items: [...cart?.items, input]
}
}
}),
}),
})
The problem lies with:
mutation AddItem($input: Any) {
addItem(input: $input){…}
There is no Any in GraphQL. The 400 is a result of an invalid query/mutation. Note that you're not actually running the same mutation that you are in GraphiQL.
Try using an input type for example in your typeDefs (on the server), add:
input addItemInput {
cartId: String!
id: String!
name: String!
price: Float!
}
Then in your client code:
const MUTATION = gql`
mutation AddItem($input: addItemInput) {
addItem(input: $input){…}
}
`
Firstly some necessary information:
When using pothos with input plugin it formulates the query type for you following the following rule: ${ParentType.name}${Field.name}Input. I hoghly recomend you follow the link and look at the docs yourself so you can understand exactly how your query should look.
Here is the link to the corresponding docs
The correct query:
const MUTATION = gql`
mutation AddItem($input:MutationAddItemInput!) {
addItem(input: $input){
items{
name
}
}
}
`;
If you get a 400 error it is probably your query is just wrong
If you get a weird error with in it check your brackets you might be missing one or two

GraphQLError: Syntax Error: Expected Name, found ":"

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!

react-admin graphql data provider: how to implement GET_MANY if GraphQL API only supports GET_ONE?

How to implement a GET_MANY data provider function in react-admin's ra-data-graphql package if the GraphQL API only supports the equivalent GET_ONE?
I understand how it can be done with REST by waiting on resolving all promises of the API call, but here the return from buildQuery is supposed to be an object with a key for the GraphQL query, and a key for a function parsing the response.
So how can this support multiple GraphQL queries, one for each ID we want to fetch, before we return the result from the data provider for GET_MANY?
#kurtko sorry for late reply. Just checking this now. Found a workaround that does not require changes to GQL schema (since that is an external API I cannot change).
You need to make changes to ra-data-graphql. Basically you need to allow for multiple GQL queries and then await until all promises resolve and return a combined result. By using either query or queries you can instruct ra-data-graphql to either run a single or multiple GQL queries. I modified index.js as follows:
// GRAPHQL QUERY
if (operation === 'query') {
if (!query.queries) {
// single GraphQL query
const apolloQuery = {
...query,
fetchPolicy: 'network-only',
...getOptions(otherOptions.query, aorFetchType, resource),
};
return client
.query(apolloQuery)
.then((response) => parseResponse(response))
.catch((error) => Promise.reject(error.message));
} else {
// multiple GraphQL queries
const prs = query.variables.map((variables) => {
const { queries, ...rest } = query;
const apolloQuery = {
...rest,
query: queries,
variables,
fetchPolicy: 'network-only',
...getOptions(otherOptions.query, aorFetchType, resource),
};
return client.query(apolloQuery);
});
return Promise.all(prs)
.then((responses) => parseResponse(responses))
.catch((error) => Promise.reject(error.message));
}
}
I had the same problem and solved with schema like this: (look {ids: [ID]} in UserFilter it's the important thing)
type Query {
Post(id: ID!): Post
allPosts(page: Int, perPage: Int, sortField: String, sortOrder: String, filter: PostFilter): [Post]
_allPostsMeta(page: Int, perPage: Int, sortField: String, sortOrder: String, filter: PostFilter): ListMetadata
User(id: ID!): User
allUsers(page: Int, perPage: Int, sortField: String, sortOrder: String, filter: UserFilter): [User]
_allUsersMeta(page: Int, perPage: Int, sortField: String, sortOrder: String, filter: UserFilter): ListMetadata
}
type User {
id: ID!
name: String!
views: Int!
}
type Post {
id: ID!
title: String!
views: Int!
body: String
user_id: ID!
User: User
}
input PostFilter {
q: String
id: ID
title: String
views: Int
views_lt: Int
views_lte: Int
views_gt: Int
views_gte: Int
user_id: ID
}
input UserFilter {
q: String
ids: [ID]
title: String
views: Int
views_lt: Int
views_lte: Int
views_gt: Int
views_gte: Int
user_id: ID
}
type ListMetadata {
count: Int!
}

graphql trouble accessing items in object

I am still trying to learn graphql and I am having trouble accessing items that are within an object in the database. In my client side code the data for id and createdAt shows up just fine it is just when I add the object that I get the error:
Expected Iterable, but did not find one for field Users.profile
I am not sure what my code is missing:
resolver:
Query: {
getUser(root, args, { userId }) {
const {id } = args;
const user = User.findOne({
id
});
return user;
}
},
schema
const User = `
type User{
id: String!
createdAt: Date
profile: [Profile]
}
type Profile {
name: String!
email: String!
}
extend type Query {
getUser(
id: String!
): User
}
How I am calling it in my client code:
const getUser = gql`
query getUser($id: String!) {
getUser(id: $id) {
id
createdAt
profile {
name
email
}
}
}
`;
This is how it looks in the MongoDB database:
user{
_id: "22222"
createdAt: 11/22/2018
profile:{
name: "Chris"
email: "chris#emample.com"
}
} `
In case it helps someone in future I had to set my objects to JSON to get it to work.
const User = `
type User{
id: String!
createdAt: Date
profile: JSON
}
extend type Query {
getUser(
id: String!
): User
}

How to pass params to child property in GraphQL

i am pretty new to GraphQL, getting to become a huge fan :)
But, something is not clear to me. I am using Prisma with and GraphQL-Yoga with Prisma bindings.
I do not know how to pass params from my graphQL server to sub properties. Don't know if this is clear, but i will show it with code, thats hopefully easier :)
These are my types
type User {
id: ID! #unique
name: String!
posts: [Post!]!
}
type Post {
id: ID! #unique
title: String!
content: String!
published: Boolean! #default(value: "false")
author: User!
}
My schema.graphql
type Query {
hello: String
posts(searchString: String): [Post]
users(searchString: String, searchPostsTitle: String): [User]
me(id: ID): User
}
and my users resolver:
import { Context } from "../../utils";
export const user = {
hello: () => "world",
users: (parent, args, ctx: Context, info) => {
return ctx.db.query.users(
{
where: {
OR: [
{
name_contains: args.searchString
},
{
posts_some: { title_contains: args.searchPostsTitle }
}
]
}
},
info
);
},
me: (parent, args, ctx: Context, info) => {
console.log("parent", parent);
console.log("args", args);
console.log("info", info);
console.log("end_________________");
return ctx.db.query.user({ where: { id: args.id } }, info);
}
};
and my posts resolver
import { Context } from "../../utils";
export const post = {
posts: (parent, args, ctx: Context, info) => {
return ctx.db.query.posts(
{
where: {
OR: [
{
title_contains: args.searchString
},
{
content_contains: args.searchString
}
]
}
},
info
);
}
};
so, now :)
I am able to do the following when i am in the GraphQL playground on my prisma service:
{
user(where: {id: "cjhrx5kaplbu50b751a3at99d"}) {
id
name
posts(first: 1, after: "cjhweuosv5nsq0b75yc18wb2v") {
id
title
content
}
}
}
but i cant do it on the server, if i do something like that.. i am getting the error:
"error": "Response not successful: Received status code 400"
this is what i am trying:
{
me(id: "cjhrx5kaplbu50b751a3at99d") {
id
name
posts(first:1) {
id
title
content
}
}
}
does somebody know how i could do that?
since i have a custom type of user, posts does not have params like the generated one. Either i am using the the generated one, or modifying it to look like this:
type User {
id: ID!
name: String!
posts(where: PostWhereInput, orderBy: PostOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Post!]
}
EDIT 2018 June 4th
# import Post from './generated/prisma.graphql'
type Query {
hello: String
posts(searchString: String): [Post]
users(searchString: String, where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [User]
me(id: ID): User
}
type Mutation {
createUser(name: String!): User
createPost(
title: String!
content: String!
published: Boolean!
userId: ID!
): Post
}
I copied the params over from prisma.graphql manually.

Resources