TypeGraphQL createUnionFunction with parameter - graphql

I'm trying to implement an extension of typegraphql's createUnionType() function to where I can pass in a class/ObjectType instead of hardcoding, and it will return a union type of both.
What I have so far doesn't work but I feel like it's possible. Could anyone provide any insight? Maybe it's not possible?
typedefs
import { ObjectType, Field, createUnionType, ClassType } from "type-graphql";
#ObjectType()
export default class MutationSuccess {
#Field()
success: boolean = true;
}
// Doesn't work
export const MutationResponse = (objectType: ClassType) => createUnionType({
name: 'MutationResponseType',
types: () => [MutationSuccess, objectType],
})
How I'm trying to use it in my resolver
#Resolver()
export default class RelationResolver {
#Mutation(() => MutationResponse(Relation), { description: 'follow user' })
async follow(
#Arg('relationInput') relationInput: RelationInput
): Promise<Relation | MutationSuccess> {
// do some stuff
}
}
error
UnhandledPromiseRejectionWarning: Error: Cannot determine GraphQL output type for follow

The Relation class need to be decorated with #ObjectType and the union type name has to be unique.

Related

Understanding React-Relay Connections in the Context of Type-GraphQL

The below code excerpt comes from the React-Relay docs on Rendering Connections. I am wondering if someone could provide me with an example of what the underlying schema definition (using `type-graphql for annotations/decorations) would look like.
const {graphql} = require('RelayModern');
const userFragment = graphql`
fragment UserFragment on User {
name
friends(after: $cursor, first: $count)
#connection(key: "UserFragment_friends") {
edges {
node {
...FriendComponent
}
}
}
}
`;
Would it look something like the following? With attention paid to the UserType type definition, and especial attention to the friends field. I am also hoping if anyone could turn my attention to a more elaborated upon example/boilerplate to help me understand what is compliant with the Relay specification. Some examples I am after:
How to type the return type of a Query if I intend one of the Query's resolved fields to be a Connection type? And what would this look when written as a fragment.
How to type the same scenario as above, except now the return type is an iterable of the original return type?
#ObjectType({ implements: [Node] })
export class UserType extends Node {
#Field()
name: string
#Field()
friends: UserConnection
}
const User = createUnionType({
name: 'User',
types: () => [UserType] as const,
resolveType: value => {
// if ('code' in value) {
// return Error
// }
return UserType
}
})
#ObjectType()
export class UserEdge extends EdgeType('report', User) {}
#ObjectType()
export class UserConnection extends ConnectionType<UserEdge>(
'user',
UserEdge
) {
}

Resolve field returns null for all fields except ID (extended type)

I have original GQL type from intermediaries microservice.
#ObjectType('Intermediary')
#Directive('#key(fields: "id")')
export class IntermediaryType implements Intermediary {
#Field(() => ID)
id: string
#Field()
beneficiaryName: string
// and other fields
}
And another GQL type that extends from external GQL type.
#ObjectType('Intermediary')
#Directive('#extends')
#Directive('#key(fields: "id")')
export class IntermediaryType {
#Field(() => ID)
#Directive('#external')
id: string
}
GQL type that nests external GQL type:
#ObjectType('FXPayment')
export class FXPaymentType {
#Field(() => ID)
id: string
#Field(() => [IntermediaryType])
intermediaries?: IntermediaryType[]
// and other fields
}
And I have a resolver for my mutation and intermediaries field.
#Resolver(() => FXPaymentType)
export class FXPaymentsResolver {
constructor(private _fxPaymentsService: FXPaymentsService) {}
#Mutation(() => FXPaymentType)
async createFXPayment(
#Args('input') input: CreateFXPaymentInput,
): Promise<FXPaymentType> {
const createdFXPayment = await this._fxPaymentsService.createFXPayment(input)
return createdFXPayment
}
#ResolveField()
intermediaries(#Parent() fxPayment: FXPaymentEntity): IntermediaryType[] {
const usedIntermediaries = [
fxPayment.nostroRequisites,
fxPayment.providerRequisites,
fxPayment.orderingRequisites,
]
return usedIntermediaries
}
}
The problem is that when mutation executed -- nested IntermediaryType contains only id field whereas other fields are nullable. I logged data in #ResolveField() and it showed me that all fields are not in null. I tried to remove #ResolveField and allow high-level resolver to resolve intermediaries field automatically (that is I just created intermediaries in my mutation) -- it doesn't work.
But still, I do really don't know what I'm doing wrong... Any attempts to forcely assign value to these fields failed also. Could you give any helpful comments on that? What should I try to do? Is everything okay with my code or not? Any ideas? Please, help.

TypeGraphql Field and Arg decorators using custom type

I'm trying to build a resolver using type-graphql library and found that I can't define custom argument type. Here is my code:
type Hits = { [K: string]: string | number }
#Resolver()
export default class SearchResolver {
#Query(() => [String], { nullable: true })
#UseMiddleware(isAuthenticated)
async searchAssetList(#Arg('hits') hits: Hits) {
return [];
}
}
I got an error:
NoExplicitTypeError: Unable to infer GraphQL type from TypeScript reflection system. You need to provide explicit type for argument named 'hits' of 'searchAssetList' of 'SearchResolver' class.
I also tried to define an input class:
type Hits = { [K: string]: string | number }
#ObjectType()
class SearchListInput {
#Field(() => GraphQLObjectType)
hits: Hits;
}
#Resolver()
export default class SearchResolver {
#Query(() => [String], { nullable: true })
async searchAssetList(#Arg('input') input: SearchListInput) {
return []
}
}
and got another error:
UnhandledPromiseRejectionWarning: Error: Cannot determine GraphQL input type for argument named 'input' of 'searchAssetList' of 'SearchResolver' class. Is the value, that is used as its TS type or explicit type, decorated with a proper decorator or is it a proper input value?
Replacing #ObjectType with #InputType also doesn't help. How to define decorators like #Field, #Arg correctly?
Any help is appreciated. Thanks.
I think you are trying to have an Arg of an array whit numbers and strings in that case you should do
#InputType()
class HitsInput
{
#Field()
Hits: [number | string];
}
#Resolver()
export default class SearchResolver {
#Query(() => [String], { nullable: true })
async searchAssetList(#Arg('input') input: HitsInput) {
return []
}
}
if this is not the case and you want an object whit dynamic fields you need to define the object, let say if hits have Name and Id_Hits,
#InputType()
class HitsInput
{
#Field()
Id_Hits: number;
#Field()
Name: string;
}
#Resolver()
export default class SearchResolver {
#Query(() => [String], { nullable: true })
async searchAssetList(#Arg('input') input: HitsInput) {
return []
}
}
and if you want to have a dynamic args base in the user request I am not quite sure that it is possible, but it is possible to do this
#InputType()
class HitsInput
{
[key: string]: any;
}
I had exactly the same issue, a couple of days ago, and I solve it using GraphQLScalarType by creating my own custom type
here how to do it
import { GraphQLScalarType} from "graphql";
export const GraphQLAny = new GraphQLScalarType({
name: 'Any',
serialize: (value) => value,
parseValue: (value) => value,
parseLiteral: (ast) => ast
});
and in your class you can use your customTpe like this:
#ObjectType()
class SearchListInput {
#Field(() => GraphQLAny)
hits: typeof GraphQLAny;
}

Does not exist on type 'DefaultRootState'. TS2339

I am trying to implement react-redux in login-form input values.
I have added values to the redux state, but I cannot access the data individually from the state object.
Here are the details:
In App.js file
console.log(useSelector((state) => state));
gives result {email: "demo#demo.com" , password: "123456"}
. I am not able to access the email inside the state object using
console.log(useSelector((state) => state.email));
It is giving the error that
'email' does not exist on type 'DefaultRootState'. TS2339
Here is the reducer.js file
let formValues = {
email: "",
password: "",
};
export const inputReducer = (state = formValues, action) => {
switch (action.type) {
case "inputValue":
return { ...state, [action.name]: action.inputValue };
default:
return state;
}
};
Here is the action.txt file
export const handleChange = (name: string, inputValue: string) => {
return {
type: "inputValue",
name: name,
inputValue: inputValue,
};
}
I wrote a function to get rid of this problem :
function getProperty<T, K extends keyof T>(o: T, propertyName: K): T[K] {
return o[propertyName]; // o[propertyName] is of type T[K]
}
You have to pass your object as first parameter, then the name of your property (here it is email or password).
If you want to get all your property at once, you have to encapsulate them in an object property like this:
{ value : {email:"alan.turing#gmail.com",password:"123" } }
i may be late but thought to provide solution. Basically this type of error message appears when you don't provide the typing in the useSelector hook
As per the doc React-Redux which states:
Using configureStore should not need any additional typings. You will,
however, want to extract the RootState type and the Dispatch type so
that they can be referenced as needed.
here in your code block the RootState type is missing, this can be declared in your store file as below
import {createStore} from 'redux';
----------
const store = createStore(rootReducer);
export default store;
export type RootState = ReturnType<typeof store.getState>;
And in your .tsx or .jsx file where exactly you want to access your store values using react-redux hook useSelector add the type as below.
useSelector((state:RootState) => state)

Defining JSON/Object type in graphql-tag

I'm kinda new to Apollo gql, just wondering if anyone know if its possible to define Object class in graphql-tag?
export const CREATE_STYLE = gql`
mutation styleCreate(
$formID: String!
$fontFamily: Object //how do you define object/JSON object?
) {
styleCreate(
formID: $formID
fontFamily: $fontFamily
) {
styleID
}
}
`;
First, if the input type is an object I would recommend to define that on the server as a input type.
In my setup I'm using:
export const createUser = gql`
mutation createUser($user: UserCreate) {
create(input: $user) {
name
email
}
}
where "UserCreate" is an interface that looks like:
export interface UserCreate {
// The user name.
name: string,
// The user email address.
email: string,
};
You can manually create the interface, but I would suggest to use apollo codegen that gives you all the input types you need.

Resources