Search code examples
typescriptnestjsprisma

How to structure JSON body for POST request in Prisma/NEST?


I have a backend which uses nest.js and Prisma.

I am trying to send a POST request but I can not understand how to satisfy Prisma autogenerated type contraints.

My prisma schema looks like this:

model Phrase {
  id Int @default(autoincrement()) @id
  word String
  definition String
  example_usage String
  createdAt DateTime @default(now())
  likes Int @default(0)
  dislikes Int @default(0)
  author Author @relation(fields:[authorId], references: [id])
  authorId Int 
  tags PhraseTags[]
}

model Author {
  id Int @default(autoincrement()) @id
  displayName String @unique
  location String
  phrases Phrase[]

}

model Tag {
  id Int @default(autoincrement()) @id
  name String
  phrases PhraseTags[]

}

model PhraseTags {
  phrase Phrase @relation(fields: [phraseId], references: [id])
  phraseId Int
  tag Tag @relation(fields: [tagId], references: [id])
  tagId Int

  @@id([phraseId, tagId])
}

my PhrasesService method which governs the creation of a Phrase looks like this:

async createPhrase(displayName, data: Prisma.PhraseCreateWithoutAuthorInput) {
    try {
      const user = await this.users.getUserByDisplayName(displayName);
      const { id } = user;
      if (user) {
        const phrase = await this.prisma.phrase.create({
          data: {
            ...data,
            author: {
              connect: {
                id,
              },
            },
         },
        });
        return phrase;
       }
     } catch (error) {
      console.log(error);
    }
}

When I try to provide a JSON which looks like this:

{
  "word": "Somevalue",
  "definition": "Ability to influence someone",
  "example_usage": "Some sample usage",
  "tags": ["cool","modern","contemporary"],
  "displayName": "Admin",
  "location": "Harbour"
}

I get this error:

Argument tags: Invalid value provided. Expected PhraseTagsCreateNestedManyWithoutPhraseInput

But when I go to PhraseTagsCreateNestedManyWithoutPhraseInput I can't really read/understand it:

export type PhraseTagsCreateNestedManyWithoutPhraseInput = {
    create?: XOR<PhraseTagsCreateWithoutPhraseInput, PhraseTagsUncheckedCreateWithoutPhraseInput> | PhraseTagsCreateWithoutPhraseInput[] | PhraseTagsUncheckedCreateWithoutPhraseInput[]
    connectOrCreate?: PhraseTagsCreateOrConnectWithoutPhraseInput | PhraseTagsCreateOrConnectWithoutPhraseInput[]
    createMany?: PhraseTagsCreateManyPhraseInputEnvelope
    connect?: PhraseTagsWhereUniqueInput | PhraseTagsWhereUniqueInput[]
  }

I have read Prisma docs, seen examples but most of them are really convoluted or super simple examples are provided as to how these types are read/understood. Could someone please assist in understanding them? What format should my tags be in?


Solution

  • In your schema, tags refers to another Prisma model: PhraseTags. If in your POST request you want to specify tags that need to be associated with a specific Phrase model, you need to tell Prisma how the PhraseTags models need to be created.

    In your specific example, Prisma expects an input of type PhraseTagsCreateNestedManyWithoutPhraseInput which gives you three options: connect, create, createMany or connectOrCreate. These options tell Prisma how to associate the PhraseTags models with your Phrase model, by either creating new instances of the PhraseTags model or connecting it to existing ones.

    create - This tells Prisma that you want to create new instances of the PhraseTags model. If you have some unique constraint/index on your PhraseTags model, this will fail if you attempt to violate it.

    createMany - Similar thing to create but with a different set of options

    connect - This tells Prisma that you always want to connect existing instances of the PhraseTags model. You must know in advance that these models exist, otherwise you'll get an error.

    connectOrCreate - Probably what you want, this tells Prisma that you want to connect instances of the PhraseTags model if they exist, otherwise create new ones.

    In your specific situation, you probably don't need the PhraseTags model at all, unless you plan on including specific information on that join table. Prisma can handle the many-to-many relationship on your behalf if you want it to.

    Documentation: https://www.prisma.io/docs/orm/prisma-schema/data-model/relations/many-to-many-relations#implicit-many-to-many-relations

    To simplify your code, I recommend changing your schema to have Phrase connect directly with Tags, then let Prisma deal with managing the implicit many-to-many relationship for you. Your API will then be a lot simpler, and you can just perform the connect/connectOrCreate operation directly between Phrase and Tag without needing another table in the middle to make things more complicated than they have to be.

    Example of how your Prisma operation will be simplified by removing the explicit table: https://www.prisma.io/docs/orm/prisma-schema/data-model/relations/many-to-many-relations#querying-an-implicit-many-to-many

    If you keep your schema like it is, then you'll need to have a lot more information about PhraseTags readily available when you perform this request, which you might not initially have and may need to fetch on demand.