-
-
Notifications
You must be signed in to change notification settings - Fork 822
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generate TypeScript/Flow types for resolvers from the schema #404
Comments
Would also love this... Did you get any further @illegalprime? |
@illegalprime Seems the topic of typing resolvers is still an open issue - graphql/graphql-js#574 - at least from a Flow perspective. There doesn't appear to be a related issue in the DefinitelyTyped repo, but something like |
I think this is definitely something that would be super high value, if someone has a design please post it here! |
This is indeed the weak link in the whole chain. I can generate TS interfaces/types from my graphql schema (SDL) using graphql-code-generator / apollo codegen and from there strongly type my client side. On the server side though, I have a disconnect between my schema and the resolvers implementation, which I can only check partially after the fact by running the server (which occasionally tells me I've done something wrong). Gaining compile-time safety here would be great. |
I think this would still be great to have! Perhaps this is something we can work on after we finish cleaning up query code generation, as part of the Apollo CLI here: https://github.com/apollographql/apollo-cli |
@prisma is working on something here; https://github.com/prisma/graphql-resolver-codegen |
In terms of desired outcome, may I suggest the following: schema.graphql type Query {
companies: [Company!]!
company(id: ID!): Company
employee(id: ID!): Employee
}
type Mutation {
registerCompany(form: CompanyRegistrationForm!): Company!
registerEmployee(form: EmployeeRegistrationForm!, companyId: ID!): Employee!
}
input CompanyRegistrationForm {
name: String!
ticker: String
}
input EmployeeRegistrationForm {
name: String!
title: String
role: EmployeeRole
}
enum EmployeeRole {
CEO
Manager
Other
}
type Employee {
id: ID!
name: String!
title: String
role: EmployeeRole
company: Company
}
type Company {
id: ID!
name: String!
ticker: String
} schema.ts // Note how optional fields in the input types are marked as optional in
// the generated TypeScript interface
export interface CompanyRegistrationForm {
name: string;
ticker?: string | null;
}
export interface EmployeeRegistrationForm {
name: string;
title?: string | null;
role?: EmployeeRole | null;
}
export enum EmployeeRole {
CEO = "CEO",
Manager = "Manager",
Other = "Other"
}
export interface Employee {
id: string;
name: string;
title: string | null;
role: EmployeeRole | null;
company: Company | null;
}
export interface Company {
name: string
ticker: string | null
}
export interface Query_company_args {
id: string;
}
export interface Query_employee_args {
id: string;
}
export interface Mutation_registerCompany_args {
form: CompanyRegistrationForm;
}
export interface Mutation_registerEmployee_args {
form: EmployeeRegistrationForm;
companyId?: string | null; // Also note how it's generated as optional
}
export type Resolver<T, Root, Args, Context> = (
root: Root,
args: Args,
ctx: Context
) => T | Promise<T>;
export interface RootResolver<Context> {
Query: {
companies: Resolver<Company[], null, {}, Context>;
company: Resolver<Company | null, null, Query_company_args, Context>;
employee: Resolver<Employee | null, null, Query_employee_args, Context>;
};
Mutation: {
registerCompany: Resolver<
Company,
null,
Mutation_registerCompany_args,
Context
>;
registerEmployee: Resolver<
Employee,
null,
Mutation_registerEmployee_args,
Context
>;
};
}
export type QueryResolver<Context> = RootResolver<Context>['Query']
export type MutationResolver<Context> = RootResolver<Context>['Mutation'] Usage example: import { Context } from "./graphql/context";
import { MutationResolver, QueryResolver, RootResolver } from "./graphql/schema";
const companies: QueryResolver<Context>['companies'] = (
root,
args,
ctx
) => { /* work it out */ }
const registerCompany: MutationResolver<Context>['registerCompany'] = (
root,
args,
ctx
) => { /* work it out */ }
const rootResolver: RootResolver<Context> = {
Query: {
companies,
// fill out with remaining resolvers
},
Mutation: {
registerCompany,
// fill out with remaining resolvers
},
}
export default rootResolver; |
@disintegrator looks nice. But what's the purpose of the |
@koenpunt good catch they aren't really used for anything. Edited and removed. |
We have already it in https://github.com/dotansimha/graphql-code-generator It generates interfaces for |
Closing in favor of above prior art as well as other alternatives (type-graphql, nexus). See also graphql/graphql-js#2188. |
So far we've been trying to implement GraphQL for our microservices at HackGT/registration#159, but when implementing a resolver I have no type definitions for the resolver or for my GraphQL schema (typescript). I've tried solutions like graphql-typewriter but the types it generates has no root parameter in the query function signature (i.e. it is
(args, context)
and not(obj, args, context)
).Does this fit under this repo or is there another solution I'm not seeing?
My current workaround is manually typing everything.
The text was updated successfully, but these errors were encountered: