Unable to fetch component data using Graphql in Strapi - graphql

I am building Graphql api with Strapi. It's a simple application which user can signup and save some of his/her information. I have two tables for that, User [Which is Strapi provided] and Profile which i use to store user additional information. The two tables has relationship
User [User has and belongs to one Profile]
Profile Profile has and belongs to one User and contact component structure.
I want to be able to fetch the current logged in user and it's information from Profile table, but the Contact field which i save as component type return null.
Here is what i am doing so far
extensions/user-permission/config/schema.graphql.js
module.exports = {
definition: `
extend type UsersPermissionsMe {
profile: ProfileMe
}
type ProfileMe {
id: ID!
website: String!
description: String!
contact: ContactMe
}
type ContactMe {
id: ID!
name: String!
phone: String!
email: String!
}
`
}
extensions/user-permission/services/User.js
'use strict';
module.exports = {
fetchAuthenticatedUser(id) {
return strapi.query('user', 'users-permissions').findOne({ id }, ['role', 'profile']);
},
};
And when run GraphQl Query
query {
me {
username
email
profile {
website
description
contact {
name
phone
email
}
}
}
}
it returned
{
"data": {
"me": {
"username": "company",
"email": "company#test.com",
"profile": {
"website": "http://localhost.com",
"description": "lorem text",
"contact": null
}
}
}
}
I want to also get contact data here. I hope someone on Internet can help me.
please help, thanks you.

Related

Graphql insert a child while indicating his parent

I'm very new into graphql but I'm able to insert a new "notification" that belongs to a "Tienda" which means store, however I'm not able to indicate to which store it belongs to.
This is the schema
type Tienda #model {
id: ID!
name: String!
cliente: [Cliente] #manyToMany(relationName: "clienteDeTienda")
news: [Notificacion] #hasMany
}
type Cliente #model {
id: ID!
name: String!
stores: [Tienda] #manyToMany(relationName: "clienteDeTienda")
}
type Notificacion #model {
id: ID!
store: Tienda #belongsTo
content: String!
}
This is how I insert a new notification:
const response = await API.graphql(graphqlOperation(createNotificacion, {input:data}))
This is what data has inside:
Object {
"content": "Nueva notificacion",
}
And this is the response I get from console.log(response):
Object {
"data": Object {
"createNotificacion": Object {
"content": "Nueva notificacion",
"createdAt": "2022-11-13T18:04:55.000Z",
"id": "9f50d333-fc9e-478f-be6a-c54275797a27",
"store": null,
"tiendaNewsId": null,
"updatedAt": "2022-11-13T18:04:55.000Z",
},
},
}
As you can see "content" was added to the notification but "store" is null but I haven't been successful in inserting the store ID in there.
This is how the mutations is defined:
export const createNotificacion = /* GraphQL */ `
mutation CreateNotificacion(
$input: CreateNotificacionInput!
$condition: ModelNotificacionConditionInput
) {
createNotificacion(input: $input, condition: $condition) {
id
store {
id
name
cliente {
nextToken
}
news {
nextToken
}
createdAt
updatedAt
}
content
createdAt
updatedAt
tiendaNewsId
}
}
`;
I've tried with the following 3 methods which give no error but still doesn't link to it's parent:
API.graphql(graphqlOperation(createNotificacion, {input:data, store:{id:'55988776-11af-42b8-b93b-9de9af35f7dc'}}))
And
API.graphql(graphqlOperation(createNotificacion, {input:data, store:'55988776-11af-42b8-b93b-9de9af35f7dc'}))
And:
API.graphql(graphqlOperation(createNotificacion, {input:data},{store:'55988776-11af-42b8-b93b-9de9af35f7dc'}))
Please somebody point me the right path or documentation about how to do this. I need to know how to perform the graphqlOperation correctly.
Thank you very much
In the end what I had to do is this:
const response = await API.graphql(graphqlOperation(createNotification, {input:{...data, storeNotificationsId:'someValidStoreId'}}));

Prisma: Field ... is not defined in ... input type OR type ... expected but non object was submitted

I'm using Prisma 1.34. fro API development. Testing it through the localhost playground.
Sorry for long text in advance, can't understand where I went wrong.
I have the following scheme representing hierarchy Script template consist of the Cards templates, and Cards include Tasks templates:
type ScriptTemplate {
id: ID!
name: String!
cards: [CardTemplate!]
input: String!
output: String!
}
type CardTemplate {
id: ID!
title: String!
description: String
tasks: [TaskTemplate!]
}
input ExistingCardTemplateInput {
id: ID!
}
input NewCardTemplateInput {
title: String!
description: String!
tasks: [NewTaskTemplateInput!]
}
type TaskTemplate {
id: ID!
label: String!
description: String!
cards: [CardTemplate!]
}
input ExistingTaskTemplateInput {
id: ID!
}
input NewTaskTemplateInput {
label: String!
description: String!
}
Corresponding mutations are:
type Mutation {
createScriptTemplate(name: String!, input: String!, output: String!, cards: [ExistingCardTemplateInput!], new_cards: [NewCardTemplateInput!]): ScriptTemplate
createCardTemplate(title: String!, description: String! tasks:[ExistingTaskTemplateInput!], new_tasks:[NewTaskTemplateInput!]): CardTemplate
createTaskTemplate(label: String!, description: String! cards:[ExistingCardTemplateInput!]): TaskTemplate
}
So basically, if I trying to use createTaskTemplate mutation or createCardTemplate mutation - everything is working fine. I can create these entities, including nested mutation creating new Card with the new Tasks in it or binding already existing Tasks. Or existing Card to newly created Task. That's why explicitly defined input types: ExistingTaskTemplateInput, NewTaskTemplateInput and NewCardTemplateInput.
Everything is working as expected when I'm trying to create a new script with the inclusion of a new Card or connecting it to an existing one, as well.
However, if I'm trying to create Script, Card and include new Tasks in it I've got error messages above.
When trying the following mutation:
mutation{
createScriptTemplate(
name: "Script via API_H2"
input: "Something describing initial state"
output: "Something describing required state at the end"
cards: [
{
id: "cjycl2nup00ta0703sd0kd8oa"
},
{
id: "cjye3ryee01ey070383sxaoxz"
}
]
new_cards:[
{
title:"New card via scriptis2"
description:"desc"
tasks: [
{
description: "test dewscription"
label: "test label"
}
]
},
{
title:"New card through scriptos2"
description: "desc"
}
]
){
id
name
input
output
createdAt
updatedAt
cards{
id
title
tasks{
id
label
}
}
}
}
I'm having error:
{
"data": {
"createScriptTemplate": null
},
"errors": [
{
"message": "Variable '$data' expected value of type 'ScriptTemplateCreateInput!' but got:
{\"name\":\"First Script through API_H2\",\"input\":\"Something describing initial state\",\"output\":\"Something describing requred state at the end\",\"cards\":{\"connect\":[{\"id\":\"cjycl2nup00ta0703sd0kd8oa\"},{\"id\":\"cjye3ryee01ey070383sxaoxz\"}],\"create\":[{\"title\":\"New card via scriptis2\",\"description\":\"desc\",\"tasks\":[{\"label\":\"test label\",\"description\":\"test dewscription\"}]},{\"title\":\"New card through scriptos2\",\"description\":\"desc\"}]}}.
Reason: 'cards.create[0].tasks'
Expected 'TaskTemplateCreateManyWithoutCardsInput', found not an object. (line 1, column 11):\nmutation ($data: ScriptTemplateCreateInput!) {\n ^",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"createScriptTemplate"
]
}
]
}
The actual request looks like this (via console.log) :
{ name: 'First Script through API_H2',
input: 'Something describing initial state',
output: 'Something describing requred state at the end',
cards:
{ connect:
[ [Object: null prototype] { id: 'cjycl2nup00ta0703sd0kd8oa' },
[Object: null prototype] { id: 'cjye3ryee01ey070383sxaoxz' } ],
create:
[ [Object: null prototype] {
title: 'New card via scriptis2',
description: 'desc',
tasks:
[ [Object: null prototype] { label: 'test label', description: 'test dewscription' } ] },
[Object: null prototype] { title: 'New card through scriptos2', description: 'desc' } ] } }
Looks like I missing {connect or create} bit for the tasks field.
However when I'm altering it to look like:
tasks: {create: [
{
description: "test dewscription"
label: "test label"
}
]
}
I'm getting error that Field \"create\" is not defined by type NewTaskTemplateInput and Field NewTaskTemplateInput.label and description of required type String! was not provided
However, this works perfectly fine (same request without tasks) :
mutation{
createScriptTemplate(
name: "Script via API_H2"
input: "Something describing initial state"
output: "Something describing required state at the end"
cards: [
{
id: "cjycl2nup00ta0703sd0kd8oa"
},
{
id: "cjye3ryee01ey070383sxaoxz"
}
]
new_cards:[
{
title:"New card via scriptis2"
description:"desc"
},
{
title:"New card through scriptos2"
description: "desc"
}
]
){
id
name
input
output
createdAt
updatedAt
cards{
id
title
tasks{
id
label
}
}
}
}
Checked generated scheme, can't spot any problems there.
input TaskTemplateCreateManyWithoutCardsInput {
create: [TaskTemplateCreateWithoutCardsInput!]
connect: [TaskTemplateWhereUniqueInput!]
}
input TaskTemplateCreateWithoutCardsInput {
id: ID
label: String!
description: String!
}
Looks like I'm confusing scheme that I defined in gql files and the one I'm doing requests again, but don't know which direction to go.
Description
First outline the entire process of a request.
The above image is taken from Prisma Basics in the official Prisma documentation.
As shown in this picture, localhost playground is the client in the figure. The Server accessed by localhost playground is the API Server in the figure, which is Prisma Client.Here is the first connection, the green arrow in the picture.
Prisma Client gets the data from the database by accessing Prisma Server. This is the second connection, the yellow arrow in the figure.
The process of data flow, sent from localhost playground to API Server to complete the first connection transmission, and then processed by resolve, use Prisma Client to send to Prisma Server to complete the second connection transmission. Prisma Server retrieves data from Database according to the requested data and returns it to API Server, completes the second connection acceptance. API Server returns the data to localhost playground, completing the acceptance of the first connection. A complete process is completed.
In the process of using Prisma, we define two schema, one for defining Prisma Server, the name is usually datamodel.prisma. The other one is used to define Prisma Client, if it is defined in the file , usually named schema.graphql, can also be defined in the JS file through the template string, there are other ways, here is not discussed in depth. What you are showing belongs to Client Schema.
Successful completion of this process requires that the data sent by each part is correct.
Your first error occurred when the second connection was sent. The data sent from API Server did not match the schema definition in Prisma Server.
The second error is that the data sent from localhost playground does not match the schema definition in API Server when the first connection is sent.
Example
Assume the following architecture
# datamodel.prisma
type User {
id: #id!
name: String!
post: [Post!]!
}
type Post {
id: #id!
title: String!
}
# schema.graphql
input CreatePost {
title: String!
}
type Mutation {
createUser(name: String!,posts:[CreatePost])
}
Use the following mutation Create user
mutation {
createUser(name: "prisma", posts: [{ title: "test" }]) {
id
name
}
}
When sent from localhost playground to API Server, the data is as follows
{
"name": "prisma",
"posts": [{ "title": "test" }]
}
If you send this data directly to Prisma Server, it does not conform to the definition of Prisma Server. You need to convert the data to a definition that conforms to the Prisma Server schema.
{
"name": "prisma",
"posts": { "create": [{ "title": "test" }] }
}
Then send it to Prisma Server via Prisma Client.
const resolve = {
Mutation: {
createUser: async (_, args) => {
const userCreateInput = {
name: args.name,
posts: {
create: args.posts,
},
}
return await prisma.createUser(userCreateInput)
},
},
}
This way the final data arrives at the database via Prisma Server.
Solve the problem
Check out the definition of createScriptTemplate in API Server.It should be that it did not convert the received data into an error caused by the format required by API Server.
Understand Prisma

Linking schema in Apollor server 2

I have a case that I'm not sure to implement, I have a REST API that returns an array of user IDs. Like this:
{
status: ""
"users": [
{
"userId": ID
},
{
"userId": ID
}
]
}
I want to have the ability to get the user details for each userID, so I want to pass the ID to another API that gets the user details.
The issue is that the second API returns the information as follows
{
status: ""
data:[{
Info:{
userId:
name:
...
}
Permissions{
...
}
...
}]
}
My issue is how can I represent this relation in the schema?
This is the schema I came up with:
Query{
EventUsersSummary(eventId: ID): EventResponse!
}
type EventResponse{
status: String!
users: [EventUser!]!
}
type EventUser {
userId: ID!
}
type User {
info: Info
permissions: Permissions
....
}
type Info{
userId: ID
firstName: String
lastName: String
email: Email
}
....
In the resolver for EventResponse I'm removing status from the result. In the resolver I plan to return the information for each user.

How can I make this as optimisticResponse?

I have a "like" button/mutation. There is still a split second while I get a response from the server. How can I make this as an optimisticResponse?
Here's my mutation:
const LIKE_MUTATION = gql`
mutation LIKE_MUTATION($postId: ID!) {
createLike(postId: $postId) {
id
post {
id
title
text
createdAt
author {
id
}
likes {
id
user {
id
}
}
}
}
}
`
Now what I'm trying to do in my Mutation component is:
optimisticResponse={{
__typename: 'Mutation',
createLike: {
__typename: 'Like',
id: this.props.post.id,
post: this.props.post,
likes: this.props.post.likes.concat({
id: 'vcjsvdcjscd',
user: { name: 'sample', id: 'jsdckbsdjcbdjs' },
}),
},
}}
the like is connected to post and to user in my schema. I'm trying to provide fake user id and name here. It doesn't work. I get this in the console as well:
Missing field id in {
"name": "user",
"__typename": "User"
}

Prisma cursor based pagination

Just finished the excellent tutorial on building Prisma based graphql backend. They explain how to implement first-offset pagination here https://www.howtographql.com/graphql-js/8-filtering-pagination-and-sorting/.
Now I am wondering, how to implement cursor-based pagination?
Here are my types (they are the same as in tutorial):
type User
implements Node {
id: ID!
name: String!
email: String!
password: String!
links(...): [Link!]
votes(...): [Vote!]
}
type Link
implements Node {
id: ID!
createdAt: DateTime!
description: String!
url: String!
postedBy(...): User
votes(...): [Vote!]
}
In the playground I am trying to query user information along with the links, created by the user:
{
user(where: {id:"cjimzqrshb3nf0c29z1p7km0j"}) {
email
links {
id
url
description
}
}
}
It gives me back all the links, created by the user. How can I paginate them? Links object does not have paging information while linksConnection does not fit inside user object.
You can query the linksConnection related to the user, and therefore access cursors :
{
linksConnection(where:{user:{id:"cjimzqrshb3nf0c29z1p7km0j"}}){
pageInfo{
endCursor
startCursor
}
edges{
cursor
}
}
}
You can implement cursor based pagination with Prisma like this:
{
users{
links(first: 10, after:"some-id") {
description
}
}
}
This is possible because the id and the cursor is the same.
Alternatively you can use offset based pagination like this:
{
users{
links(first: 10, skip: 30) {
description
}
}
}

Resources