Front end Mutation call won't resolve - react-native

I have a react-native mobile app making a call to a graphql backend. Queries are working without issue. I just coded a mutation however, and everytime I try to make a call, the client is raising this issue:
Error: Could not find a default resolver for travelPassPasswordResetEmail. Please supply a resolver for this mutation.: {"response":{"errors":[{"message":"Could not find a default resolver for travelPassPasswordResetEmail. Please supply a resolver for this mutation.","locations":[{"line":2,"column":3}],"path":["travelPassPasswordResetEmail"]}],"data":null,"status":201,"headers":{"map":{"content-type":"application/json"}}},"request":{"query":"mutation travelPassPasswordResetEmail($email: String) {\n travelPassPasswordResetEmail(email: $email) {\n message\n status\n }\n}","variables":{"email":"test#test.com"}}}
We are using graphql-codegen.
The mutation in the schema:
type Mutation {
travelPassPasswordResetEmail(email: String): SetResetPasswordMutation!
}
The operations graphql file:
mutation travelPassPasswordResetEmail($email: String) {
travelPassPasswordResetEmail(email: $email) {
message
status
}
}
In the types files we get the following generated for the mutation:
export const TravelPassPasswordResetEmail = gql`
mutation travelPassPasswordResetEmail($email: String) {
travelPassPasswordResetEmail(email: $email) {
message
status
}
}
`;
export const TravelPassPasswordResetEmailDocument = gql`
mutation travelPassPasswordResetEmail($email: String) {
travelPassPasswordResetEmail(email: $email) {
message
status
}
}
`;
export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper = defaultWrapper) {
return {
travelPassPasswordResetEmail(variables?: TravelPassPasswordResetEmailMutationVariables, requestHeaders?: Dom.RequestInit["headers"]): Promise<TravelPassPasswordResetEmailMutation> {
return withWrapper((wrappedRequestHeaders) => client.request<TravelPassPasswordResetEmailMutation>(TravelPassPasswordResetEmailDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'travelPassPasswordResetEmail');
}
};
}
Does anyone know why this is asking for a resolver and it cannot be found? I have tested the graphql on the backend with postman and everything is ok.

Related

Nuxt 3 - Server not ready on mount, Volar engine confused

I have two issues that may or may not be related.
Overview
Folder Structure
pages
|---user.vue
server
|---api
|---profile.get.ts
|---profile.post.ts
The tech is Nuxt3 using the server and Supabase.
profile.get.ts
import { serverSupabaseClient, serverSupabaseUser } from "#supabase/server"
import { Database } from "~~/types/supabase"
export default defineEventHandler(async (event) => {
try {
const supabase = serverSupabaseClient<Database>(event)
const user = await serverSupabaseUser(event)
const query = getQuery(event)
const { data, error } = await supabase.from('profiles').select('*').eq('email', query.email).single()
if (error) throw { status: error.code, message: error.message }
return { displayName: data.display_name, avatarUrl: data.avatar_url }
} catch (err) {
console.error('Handled Error:', err)
}
})
profile.post.ts
import { serverSupabaseClient } from "#supabase/server"
import { Database } from "~~/types/supabase"
export default defineEventHandler(async (event) => {
const supabase = serverSupabaseClient<Database>(event)
const { displayName, avatarUrl, email }: { displayName: string, avatarUrl: string, email: string } = await readBody(event)
const { error } = await supabase.from('profiles').update({ display_name: displayName, avatar_url: avatarUrl }).match({ email })
if (error) throw new Error(error.message)
return { status: 200 }
})
user.vue Snippet
onMounted(() => {
setTimeout(() => {
getProfile()
}, 100) // Fails when around 50 or less
})
async function getProfile() {
const { data, error } = await useFetch('/api/profile', { method: 'GET', params: { email: user.value?.email } })
console.log(data.value)
console.log(error.value)
displayName.value = data.value!.displayName || ''
avatarUrl.value = data.value!.avatarUrl || ''
}
Problem 1
When user.vue mounts, I want to call my Nuxt API (profile.get.ts) and fetch user data (display name, avatar url) from the Supabase database. However, I receive this error when fetching on mount: FetchError: 404 Cannot find any route matching /api/profile. (/api/profile). However, if I use setTimeout to 100ms, it fetches fine. That makes me think the API server is simply not ready, but the documentation doesn't mention that and encourages fetching during lifecycle.
Problem 2
Volar seems to be confused about the typing of data from getProfile().
Property 'displayName' does not exist on type '{ status: number; } | { displayName: string | null; avatarUrl: string | null; }'.
Property 'displayName' does not exist on type '{ status: number; }'.ts(2339)
However, this is the typing from profile.post.ts even though I'm using profile.get.ts.
Current Behavior
Without setTimeout at 100ms or greater, it will fail with the 404 message
With setTimeout at 100ms or greater, or with getProfile() called from a button, there is no issue, even with the TypeScript errors, etc.
Desired Behavior
TypeScript correctly recognizes the proper endpoint (profiles.get.ts since I'm calling it with get)
Data can be fetched on mount from the API without the use of setTimeout

NextJS API route error "TypeError: res.status is not a function"

I created a simple api endpoint named getFeed which is supposed to get feed content from Sanity CMS. But unexpectedly the endpoint is throwing an error "res.status is not a function". I know there is a similar question asked here , but in my case the api endpoint file is stored in the supposed pages/api directory. Here is the code snippet below.
import { NextApiResponse } from 'next'
import { client } from '../../lib/sanity/sanity'
export default async function getFeed(res: NextApiResponse) {
try {
const feeds = await client.fetch(
`*[_type == "post"]
{
_createdAt,
title,
description,
picture,
postDocId,
postedByUserId,
postedByUserName,
postedByUserImage
}`
)
return res.status(200).json({ feeds })
} catch (error) {
return res.status(500).json({ message: "Couldn't get post feed:\n", error })
}
}
Here is my folder structure
What am I doing wrong??
Try to specify also the req parameter and add a type to the response:
import { NextApiRequest, NextApiResponse } from 'next'
interface Data {
message?: string;
feeds?: <type-of-feeds>[];
}
export default async function getFeed(req: NextApiRequest, res: NextApiResponse<Data>) { ... }

Cannot read property 'context' of undefined - GraphQL

I am using Typescript, Express, TypeORM, GraphQL and TypeGraphQL to build a small app that allows the user to login.
However, when I hit my test query bye on the GraphQL playground, I get:
Cannot read property 'context' of undefined
"TypeError: Cannot read property 'context' of undefined",
" at new exports.isAuth // isAuth is a JS file I wrote
MyContext.js
import { Request, Response } from "express";
export interface MyContext {
req: Request;
res: Response;
payload?: { userId: string };
}
isAuth.js
import { MiddlewareFn } from "type-graphql";
import { verify } from "jsonwebtoken";
import { MyContext } from "./MyContext";
export const isAuth: MiddlewareFn<MyContext> = ({ context }, next) => {
const authorization = context.req.headers["authorization"];
if (!authorization) {
throw new Error("not authorized");
}
...
UserResolver
#Query(() => String)
#UseMiddleware(isAuth)
bye(#Ctx() { payload }: MyContext) {
console.log(payload);
return `your user id is: ${payload!.userId}`;
}
I am not sure why the context is undefinied in the file isAuth.js
SOLVED thanks to: https://github.com/MichalLytek/type-graphql/issues/433
1) Go into ./tsconfig.json
2) Change "target": "es5" to "target": "es6"

GraphQL - Apollo Client without using hooks?

I am attempting to use the Apollo GraphQL Client for React Native. However, in some parts of my app I need to do a mutation on the GraphQL data, in such a way that the interface should not be exposed to the user.
For instance, on my sign up page, I want to create a user in the database, but only after I have gone through and verified everything, created a uuid, etc. (things that require a class). If the call is sucessful, I want to imediately move on to the home page of the app. If not, I want to notify the user.
As such, I need access to do a GraphQL request, without hooks and just using callbacks to change the UI. Is this possible, and how could this be done?
The documentation does a bad job of explaining it, but you can simply call query or mutate on the ApolloClient object. https://www.apollographql.com/docs/react/api/core/ApolloClient/#apolloclient-functions
Compared to the other answer, this is probably better than making a raw call with just fetch because it uses the same cache layer as the rest of your application, instead of going around it.
const apolloClient = new ApolloClient({
uri: "/graphql",
cache: new InMemoryCache()
})
const qr = gql`
query {
getCustomers() {
name
}
}
`
const result = await apolloClient.query({
query: qr ,
variables: {}
})
Yes, its possible.
A call to the GraphQL service simply expects a key-value pair of query or mutation in the body with the query/mutation you're trying to send.
You can do this with a simple fetch request as POST, or a cURL, or via postman... It doesn't really matter as long as its a POST request.
See also here.
Yes, It is possible as a matter of fact I am leaving sample classes that can be used for both query and mutation.
First, configure your application to work with graphQl.
Wrap your app with the provider.
import { client } from './config/connection';
import { ApolloProvider } from '#apollo/client';
<ApolloProvider client={client}>
<App/>
</ApolloProvider>
Here is the client that we want to
import { ApolloClient, ApolloLink, InMemoryCache } from '#apollo/client';
export const client = new ApolloClient({
cache: new InMemoryCache(),
uri: 'http://localhost:4000/graphql',
});
Operations.js (Contains Queries And Mutations gql)
import { gql } from '#apollo/client';
export const Query_SignIn = gql`
query Login($email: String!, $password: String!) {
login(email: $email, password: $password) {
name
}
}
`;
export const Mutate_SignUp = gql`
mutation SignUp($name: String!, $email: String!, $password: String!, $passwordConfirmation: String!) {
signUp(name: $name, email: $email, password: $password, passwordConfirmation: $passwordConfirmation) {
name
}
}
`;
A Class using query instead of useQuery hook
import { Query_SignIn } from '../../../operations';
class login {
constructor(client) {
this._client = client;
}
async signIn(email, password) {
const response = await this._client.query({
query: Query_SignIn,
variables: {
email,
password,
},
});
return response;
}
}
export default login;
A class using mutate instead of useMutation
import { Mutate_SignUp } from '../../../operations';
class register {
constructor(client) {
this._client = client;
}
async signUp(accountType, name, email, password, passwordConfirmation) {
const response = await this._client.mutate({
mutation: Mutate_SignUp,
variables: {
name,
email,
password,
passwordConfirmation,
},
});
return response;
}
}
export default register;

GraphQL field's resolver not getting called

I'm using apollo-server and testing using GraphiQL in my browser. I set up my resolvers based on Apollo's GitHunt-API example, but the resolver on the field "review.extraStuff" never gets called.
Resolver
const rootResolvers = {
review(root, args, context) {
console.log('resolving review');
return {'HasErrors': true}
}
}
const extraStuff = (root, args, context) => {
console.log('resolving extraStuff');
return "yes";
}
rootResolvers.review.extraStuff = extraStuff;
export default {
RootQuery: rootResolvers
};
Schema
const Review = `
type Review {
HasErrors: Boolean
extraStuff: String
}
`
const RootQuery = `
type RootQuery {
review(id: String!): Review
}
`;
const SchemaDefinition = `
schema {
query: RootQuery
}
`;
Query result from GraphiQL
Additional Info
I know that Apollo is aware of my extraStuff resolver because if I set "requireResolversForNonScalar" to true, I don't get a message telling me extraStuff is missing a resolve function. I've added logging to both the schema and the apolloExpress middleware and learned nothing.
My problem was that I didn't understand that the resolvers you pass into makeExecutableSchema (from graphql-tools) needs to map all your types to their own resolvers. In other words, every type should have a top-level entry in the resolvers object you pass to makeExecutableSchema.
Here's how I fixed my problem:
Resolvers
const rootResolvers = {
review(root, args, context) {
console.log('resolving review');
return {'HasErrors': true}
}
}
const reviewResolvers = {
extraStuff(root, args, context) {
console.log('resolving extraStuff');
return "yes";
}
}
export default {
RootQuery: rootResolvers
Review: reviewResolvers
};
No changes were necessary in my schema, or anywhere else for that matter.