4

I have the following datamodel:

type Job { 
    // ...
    example: String
    selections: [Selection!]
    // ...
}

type Selection { 
    ...
    question: String
    ...
}

I define my object type so:

export const Job = prismaObjectType({
  name: 'Job',
  definition(t) {
    t.prismaFields([
      // ...
      'example',
      {
        name: 'selections',
      },
      // ...
    ])
  },
})

I do my resolver this way:

t.field('createJob', {
  type: 'Job',
  args: {
    // ...
    example: stringArg(),
    selections: stringArg(),
    // ...
  },
  resolve: (parent, {
    example,
    selections
  }, ctx) => {
    // The resolver where I do a ctx.prisma.createJob and connect/create with example
  },
})

So now in the resolver I can receive the selections as json string and then parse it and connect/create with the job.

The mutation would look like this:

mutation {
  createJob(
    example: "bla"
    selections: "ESCAPED JSON HERE"
  ){
    id
  }
}

I was wondering if there's anything more elegant where I could do something like:

mutation {
  createJob(
    example: "bla"
    selections: {
       question: "bla"
    }
  ){
    id
  }
}

or

mutation {
  createJob(
    example: "bla"
    selections(data: {
      // ...
    })
  ){
    id
  }
}

I've noticed that with nexus-prisma you can do stringArg({list: true}) but you can't really do objects.

My main question is what is the most elegant way to do either nested mutation or connect all in one.

Trufa
  • 39,971
  • 43
  • 126
  • 190

1 Answers1

5

You can use an inputObjectType as shown in the docs:

export const SomeFieldInput = inputObjectType({
  name: "SomeFieldInput",
  definition(t) {
    t.string("name", { required: true });
    t.int("priority");
  },
});

Make sure to include the type as part of the types you pass to makeSchema. You can then use it to define an argument, like

args: {
  input: arg({
    type: "SomeFieldInput", // name should match the name you provided
  }),
}

Now, the argument value will be available to your resolver as a regular JavaScript object, not a String. If you need a list of input objects, or want to make the argument required, you do so using the same options you would provide with when using a scalar -- list, nullable, description, etc.

Here's a complete example:

const Query = queryType({
  definition(t) {
    t.field('someField', {
      type: 'String',
      nullable: true,
      args: {
        input: arg({
          type: "SomeFieldInput", // name should match the name you provided
        }),
      },
      resolve: (parent, { input }) => {
        return `You entered: ${input && input.name}`
      },
    })
  },
})

const SomeFieldInput = inputObjectType({
  name: "SomeFieldInput",
  definition(t) {
    t.string("name", { required: true });
  },
});

const schema = makeSchema({
  types: {Query, SomeFieldInput},
  outputs: {
    ...
  },
});

Then query it like:

query {
  someField(
    input: {
       name: "Foo"
    }
  )
}

Or using variables:

query($input: SomeFieldInput) {
  someField(input: $input)
}
Kashif Nazar
  • 20,775
  • 5
  • 29
  • 46
Daniel Rearden
  • 80,636
  • 11
  • 185
  • 183
  • This seems exactly what I need will review and probably assign bounty thanks a bunch! Is the documentation not very clear or is it me?? Thanks you!! – Trufa Apr 30 '19 at 10:29
  • Yeah, `nexus` is pretty new and the docs are pretty sparse. They're accepting PRs for any corrections or additions to the docs though :) – Daniel Rearden Apr 30 '19 at 11:29
  • FWIW I updated the answer with a more complete example schema – Daniel Rearden Apr 30 '19 at 11:30
  • Hey! I never really checked since I had already implemented it the other way, I'm getting: `Error: Expected SomeFieldInput to be a valid output type, saw GraphQLInputObjectType` any ideas? Thanks! Sorry for the late reply! – Trufa Nov 17 '19 at 19:45