Skip to content
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

Backing types #302

Open
Weakky opened this issue Jun 24, 2019 · 3 comments
Open

Backing types #302

Weakky opened this issue Jun 24, 2019 · 3 comments
Labels
scope/resolving Relates to implementing resolvers type/feat Add a new capability or enhance an existing one

Comments

@Weakky
Copy link
Member

Weakky commented Jun 24, 2019

How they're currently working

Backing types represent the typescript types used to define the root of a resolver.

So far, they have been either inferred by nexus or defined using the typegenAutoConfig nexus global configuration.

Nexus itself cannot infer too much from the object type definitions. For now, it only infer the fields which don't have resolvers, assuming that if you don't have a resolver for a field, it means the parent needs to pass the value down.

Proposal

Given the following object type:

const User = objectType({
  name: 'User',
  definition(t) {
    t.id('id')
    t.string('name')
    t.field('posts', {
      type: 'Post',
      list: true,
      resolve(root, args, ctx) {
        return ctx.photon.user.findOne({ root.id }).posts()
      }
    })
  }
})

Nexus will infer the following Typescript type:

interface User {
  id: string
  name: string
}

Meaning, any parent type of User (such as Query) will need to pass an id and name property to the User type because they don't have resolvers and therefore rely on a default resolver.

Limitations:

  • Because you provide a resolver to a field doesn't mean you don't need that same field to be passed from the parent. You might want to just return it as a default resolver would do, but add some analytics or other integration. Currently, In that case, you need to provide your own typescript type to override the one inferred by nexus.
  • Using nexus' typegenAutoConfig is limited as it assumes there's a 1-1 mapping between your backing type name and your graphql type. You can override that as well using the typegenAutoconfig.backingTypeMap, but that's not convenient at all. It also doesn't allow for additive backing type field.

What we need

We need a way to express the backing type requirements on a field/type level.

If we had such an api, each resolvers could additionally express the backing type requirements.

Let's imagine a simple api:

export const User = objectType({
  name: 'User',
  definition(t) {
    t.id('id')
    t.string('name')
    t.field('posts', {
      type: 'Post',
      list: true,
      addToBackingType: true // Additively merge `posts` to the inferred backingType
      resolve(root, args, ctx) {
        ctx.googleAnalytics.trackSomething()

        return root.posts
      }
    })
  }
})

addToBackingType would force posts to be inferred by nexus and therefore generate the following backing type:

interface User {
  id: string
  name: string
  posts: Post[]
}

interface Post {
  ...
}

It might be that your backingType field is named differently than what you want to expose, or that it doesn't have the same shape at all. In that case, your backingType could also be expressed as

{
  addToBackingType: { name: 'namedNeededFromParent', type: `{ id: string, title: string }` }
}

Finally, it might be that you need to add a field to your backingType even though it's not exposed at all in your GraphQL API. For that, we have two solutions:

n°1: On a field level

objectType({
  name: 'SomeType',
  definition(t) {
    t.model.someField({ hide: true })
  }
})

By hiding a field, it'd simply add it to the backingTypes while not exposing it on the API layer

n°2: On a type level

objectType({
  name: 'SomeType',
  definition(t) {
    t.model.addToBackingType('{ id: string, name: string }')
  }
})
@Weakky Weakky added the v2 label Jun 24, 2019
@jasonkuhrt jasonkuhrt added type/feat Add a new capability or enhance an existing one and removed v2 labels Sep 5, 2019
@jasonkuhrt
Copy link
Contributor

n°2: On a type level

Is there anything about this that is tied to nexus-prisma? Doesn't seem like it.

@jasonkuhrt jasonkuhrt added the scope/resolving Relates to implementing resolvers label Sep 5, 2019
@Weakky
Copy link
Member Author

Weakky commented Sep 10, 2019

Is there anything about this that is tied to nexus-prisma? Doesn't seem like it.

Nope, I don't think so. Ideally, that would be implemented on nexus. This issue actually covers the same topic as graphql-nexus/nexus#216

@jasonkuhrt
Copy link
Contributor

@Weakky suggestion:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
scope/resolving Relates to implementing resolvers type/feat Add a new capability or enhance an existing one
Projects
None yet
Development

No branches or pull requests

2 participants