nexus
nexus copied to clipboard
excess fields from root resolver not typed
The code explains it all:
export const SomeObjectType = objectType({
name: SomeObject.$name,
description: SomeObject.$description,
definition(t) {
t.field(SomeObject.id);
t.field(SomeObject.name);
t.string("url", {
resolve(root) {
return `www.url.com/${root.slug}`; // <- id not typed
},
});
},
});
const queries = extendType({
type: "Query",
definition: (t) => {
t.list.field("someObject", {
type: "SomeObject",
args: {
someObjectId: nonNull(stringArg()),
},
resolve: (_, { someObjectId }, ctx) => {
return ctx.prisma.someObject.findMany({ // returns also slug property
where: {
someObjectId,
},
});
},
});
},
});
When the root resolver returns slug
, the field resolver does not know about it. Should I do something differently, or is this valid use case & a bug? I don't want to reveal the slug
to the client as is since it's unnecessary. This example is simplified and in reality I'm returning signed url and the data needed for it is not to be shown to the client side.
I'm using nexus-prisma
which might affect but I think the issue is in nexus instead.
I encounter this same issue, maybe it would be nice to declare private values
that are not expose to the client but rather only available on server with their own typesafety
Hmm yeah, something like t.private.field(SomeObject.slug);
could work. Or then in the resolver:
t.string("url", {
requires: [t.field(SomeObject.slug)],
resolve(root) {
return `www.url.com/${root.slug}`;
},
});
Both are somewhat verbose, but would roughly follow the current conventions.
@jasonkuhrt would not want to push this, but this is maybe the biggest issue type wise in nexus at the moment. The types of root
variable are virtually always wrong.
Maybe something like:
type InputType = {
id: string;
name: string,
slug: string;
}
export const SomeObjectType = objectType<InputType>({
name: SomeObject.$name,
description: SomeObject.$description,
definition(t) {
t.field(SomeObject.id);
t.field(SomeObject.name);
t.string("url", {
resolve(root) { // <- InputType
return `www.url.com/${root.slug}`; // <- id typed now!
},
});
},
});
could work? And when you do:
const queries = extendType({
type: "Query",
definition: (t) => {
t.list.field("someObject", {
type: SomeObjectType,
args: {
someObjectId: nonNull(stringArg()),
},
resolve: (_, { someObjectId }, ctx) => {
return {
smthng: 123 // type error since it does not match the InputType of SomeObjectType
}
},
});
},
});
This would separate the GraphQL type from the input for that type. There might also be a smoother way to do this, but at least this could be a good MVP.
This is my only pain point wit nexus. For now, we've gone with deprecating the private field:
t.string("user_id", { deprecation: `Use "user" instead` });
t.string("user", {
resolve(root) {
return getUser(root.user_id);
},
});