Issues joining tables in GraphQL resolvers, thrown 400 error - javascript

I am trying to join MySQL tables using GraphQL and keep receiving a 400 error code:
"Response not successful: Received status code 400"
This is how I am querying my data:
{
users {
usr_last_name
business {
bus_name
}
}
}
# or
{
user(usr_id:1) {
usr_last_name
business {
bus_name
}
}
}
Here are my resolvers for User.
export const resolvers = {
Query: {
users: async() => db.user.findAll(),
user: async(obj, args, context, info) => db.user.findByPk(args.usr_id)
},
Mutation: {...},
User: {
business: async(obj, args, context, info) => { // This is not getting hit :/
return db.business.findAll({where: {bus_user_id: args.usr_id}});
}
}
};
(Note that I can query Business with no issues)
Thanks,

The problem was I forgot to put business: Business in the type definition for the type user:
type User {
usr_id: ID
usr_first_name: String
usr_last_name: String
usr_email: String
usr_password: String
usr_create_date: Int
usr_delete_date: Int,
business: Business
}

Related

Prisma result processing into single object

I'm working on a nextjs 13 project with prisma ORM with MongoDB. Currently I am trying to fetch roles with permissions for admin role matrix. This is the Role model schema.
model Role {
id String #id #default(auto()) #map("_id") #db.ObjectId
name String #unique
userIDs String[] #db.ObjectId
users User[] #relation(fields: [userIDs], references: [id])
permissions String[]
##map("roles")
}
When fetching the records I'd like to process them a little. Running this query returns such result.
const roles = await prisma.role.findMany({
select: {
name: true,
permissions: true,
}
})
console.log(roles);
[
{ name: 'User', permissions: [ 'permissions.user.view.dashboard' ] },
{
name: 'Admin',
permissions: [
'permissions.admin.view.dashboard',
'permissions.user.view.dashboard'
]
}
]
I need the results in one object with role name prepended to the permission like so
{
'User.permissions.user.view.dashboard',
'Admin.permissions.user.view.dashboard',
'Admin.permissions.admin.view.dashboard'
}
So my question is how would I do this? Preferably directly in prisma, but if it's not possible javascript will do.
It's not possible to transform this object directly at Prisma level.
You can achieve this transformation like this:
import { PrismaClient } from '#prisma/client';
const prisma = new PrismaClient();
async function main() {
const roles = await prisma.role.findMany({
select: {
name: true,
permissions: true,
},
});
console.log(roles);
const updatedRoles = [];
roles.forEach((role) => {
role.permissions.forEach((permission) => {
updatedRoles.push(`${role.name}.${permission}`);
});
});
console.log(updatedRoles);
}
main()
.catch((e) => {
throw e;
})
.finally(async () => {
await prisma.$disconnect();
});
Here's the sample response:

Axios & Typescript: Return array object with only the props specified

I'm trying to build an API that fetches the ERC20 tokens in my balance. For this, I'm using nextjs & axios with TypeScript.
The issue I have is that the response outputed by my endpoint returns way too much data, rather than the only 3 props defined in my Token type. Here is how it goes:
util/api.ts
import axios from 'axios';
import console from 'console';
type Token = {
contractAddress: string;
tokenName: string;
tokenSymbol: string;
};
async function getTokens(walletAddress: string) {
const params = {
action: 'tokentx',
address: walletAddress,
offset: 5,
startblock: 0,
endblock: 999999999,
sort: 'asc',
apikey: 'XXXXX'
}
try {
const response = await axios.request<Token[]>({
url: 'https://api.etherscan.io/api?module=account',
params: params
}).then((response) => {
return response.data
});
return response
} catch (error) {
if (axios.isAxiosError(error)) {
console.log('error message: ', error.message);
return error.message;
} else {
console.log('unexpected error: ', error);
return 'An unexpected error occurred';
}
}
}
export async function getWalletBalance(walletAddress: string) {
let tokens = await getTokens(walletAddress)
return tokens
}
pages/api/balances/[network]/[wallet.ts]
import { NextApiRequest, NextApiResponse } from "next";
import NextCors from "nextjs-cors";
import { getWalletBalance } from "../../../../util/api";
export default async (req: NextApiRequest, res: NextApiResponse) => {
await NextCors(req, res, {
methods: ["GET"],
origin: "*",
optionsSuccessStatus: 200,
});
const { wallet } = req.query as { wallet: string };
try {
const balance = await getWalletBalance(wallet);
res.json({ balance });
} catch (e) {
res.status(400).json({ error: (e as Error).message });
}
};
How can I make it so that getTokens() only returns an array of Token with only the contractAddress, tokenName, tokenSymbol props, in order for the endpoint to output only the JSON I need?
If you're looking to reduce the data returned from the api.etherscan.io
in your own proxy api you'd need to filter out only the props you need. you can achieve it like so:
.then((response) => {
return response.data.map(x=>({
contractAddress:x.contractAddress
tokenName:x.tokenName
tokenSymbol:x.tokenSymbol
});
})
I don't know much about the 3rd party endpoint but I assuming its a REST endpoint so you couldn't take advantage of Graphql's ability to reduce overfetching by specifying the properties of the type you're interested in.

Prisma throws an error "TypeError: cannot read property findmany of undefined"

I wanted to make a chat app to practice working with graphql and node, for database I used prisma. I was doing everything like in this tutorial.
https://www.howtographql.com/graphql-js/0-introduction/
I just changed variable names.
so I have this code
const { PrismaClient } = require('#prisma/client')
const prisma = new PrismaClient()
const resolvers = {
Query: {
history: async (parent, args, context) => {
return context.prisma.Messages.findMany()
},
},
Mutation: {
post: (parent, args, context) => {
const newMessage = context.prisma.Messages.create({
data: {
username: args.username,
message: args.message,
},
})
return newMessage
},
},
}
const server = new GraphQLServer({
typeDefs: './src/schema.graphql',
resolvers,
context: {
prisma,
}
})
server.start(() => console.log(`Server is running on http://localhost:4000`))
as my index.js
this is my schema.prisma
provider = "sqlite"
url = "file:./dev.db"
}
generator client {
provider = "prisma-client-js"
}
model Message {
id Int #id #default(autoincrement())
sendedAt DateTime #default(now())
message String
username String
}
script.js
const { PrismaClient } = require("#prisma/client")
const prisma = new PrismaClient()
async function main() {
const newMessage = await prisma.Messages.create({
data: {
message: 'Fullstack tutorial for GraphQL',
username: 'www.howtographql.com',
},
})
const allMessages = await prisma.Messages.findMany()
console.log(allMessages)
}
main()
.catch(e => {
throw e
})
// 5
.finally(async () => {
await prisma.disconnect()
})
and schema.graphql
type Query {
history: [Message!]!
}
type Mutation {
post(username: String!, message: String!): Message!
}
type Message {
id: ID!
message: String!
username: String!
}
and that is what i got in my playground
"data": null,
"errors": [
{
"message": "Cannot read property 'findMany' of undefined",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"history"
]
}
]
}
please help
I managed to fix that. Actually, all I needed was to use the same name but lowercased as in schema.prisma
It should be noted it is not actually lowercase but camel case.
Example:
Model name: Message -> Prisma client name: message
Model name: MessagePerUser -> Prisma client name: messagePerUser
Would like to add on to the answer
Basically when calling await prisma.User.create, prisma allows the User model to be in caps, but when calling other models such as prisma.messages.create the m has to be in lowercase. Essentially,for all prisma calls, the models should be in lowercase. Hopefully this answers your question, prisma does not flag this error out
use Table name as camelCase in prisma Client to make Queries
Example:
Table Name is: StudentData
then use camelCase according to table name
prisma.studentData.findMany();

How to override default resolver in Apollo Server if it automatically triggers Sequelize query?

Application uses Apollo Server and Sequelize as an ORM. I thought that every custom type needs a custom resolver, however in case of Post and Author types, post author is resolved automatically, therefore I cannot modify this logic to resolve N+1 problem.
Minimal example of schema could look like this
type Post {
id: ID!
author: User!
}
type User {
id: ID!
username: String!
}
And resolver
const postsResolver = {
Post: {
author: async (post) => User.findByPk(post.authorId)
}
Query: {
posts: async () => Posts.findAll()
}
}
The problem is that when I deleted author resolver, nothing has changed and it still returns author.
Is there any way to override default resolver?
These two objects do the exact same thing (which they shouldn't)
// With author resolver
const postsResolver = {
Post: {
author: async (post) => User.findByPk(post.authorId)
}
Query: {
posts: async () => Posts.findAll()
}
}
// Without author resolver
const postsResolver = {
Query: {
posts: async () => Posts.findAll()
}
}

GraphQL Apollo: Variable was not provided error in apollo client query, although I think I set the variable

What is wrong with this basic apolloClient query?
import gql from 'graphql-tag'
export default (context, apolloClient, userId) => (
apolloClient.query({
query: gql`
query RootQueryType($userId: ID!) {
verifyUser(
id: $userId
) {
id,
token
}
},
`,
options: {
variables: { userId: userId }
}
}).then(({ data }) => {
return { loggedInUser: data }
}).catch((error) => {
console.log(error)
return { loggedInUser: {} }
})
)
I do get the error Error: GraphQL error: Variable "$userId" of required type "ID!" was not provided.. But I set the options and variables with this data.
I don't see, what I am doing wrong.
I think you have the problem in the query definition:
gql `
query RootQueryType($userId: ID!) {
verifyUser(
userId: $userId // here you need the parameter to be userId
) {
id,
token
}
}`
The first userID should be id instead of userID, it should also be defined as id in the Apollo server to match your query..
Change:
options: {
variables: { userId: userId }
}
To:
options: {
variables: { id: userId }
}
I came across this issue. Make sure your variable is
string "userId": "1" not number "userId": 1
without $ sign "userId": "1" not "$userId": "1" also not userId
I was setting as $userId: 1 but correct one was "userId": "1"

Categories