Dgraph data is not accessible via graphql if added via DQL mutation - graphql

What I want to do
Add data using DQL mutation https://github.com/dgraph-io/dgo#running-a-mutation and these data to also be visible via graphql.
Dgraph version: v21.03.2
DQL schema:
<Product.created_at>: datetime .
<Product.image>: string .
<Product.name>: string #index(hash) #upsert .
<Product.slug>: string #index(hash) #upsert .
<Product.updated_at>: datetime .
<dgraph.drop.op>: string .
<dgraph.graphql.p_query>: string #index(sha256) .
<dgraph.graphql.schema>: string .
<dgraph.graphql.xid>: string #index(exact) #upsert .
type <Product> {
Product.name
Product.slug
Product.image
Product.created_at
Product.updated_at
}
type <dgraph.graphql> {
dgraph.graphql.schema
dgraph.graphql.xid
}
type <dgraph.graphql.persisted_query> {
dgraph.graphql.p_query
}
GraphQL schema:
type Product {
id: ID!
name: String! #id #dgraph(pred: "Product.name")
slug: String! #id #dgraph(pred: "Product.slug")
image: String #dgraph(pred: "Product.image")
created_at: DateTime! #dgraph(pred: "Product.created_at")
updated_at: DateTime! #dgraph(pred: "Product.updated_at")
}
Using the above schema, graphql queries are working fine.
Graphql mutation
mutation MyMutation {
addProduct(input: {name: "product 1", slug: "prod-1", created_at: "2021-10-04T06:37:57.707227339Z", updated_at: "2021-10-04T06:37:57.707227339Z"}) {
numUids
}
}
Graphql Query
query MyQuery {
queryProduct {
name
}
}
response of the graphql query:
{
"data": {
"queryProduct": [
{
"name": "product 1"
}
]
},
"extensions": {
"touched_uids": 2,
"tracing": {
"version": 1,
"startTime": "2021-10-04T06:42:01.064395081Z",
"endTime": "2021-10-04T06:42:01.065675778Z",
"duration": 1280687,
"execution": {
"resolvers": [
{
"path": [
"queryProduct"
],
"parentType": "Query",
"fieldName": "queryProduct",
"returnType": "[Product]",
"startOffset": 110469,
"duration": 1164739,
"dgraph": [
{
"label": "query",
"startOffset": 149859,
"duration": 1123999
}
]
}
]
}
}
}
}
Then I did a mutation using dgo: https://github.com/dgraph-io/dgo#running-a-mutation and the data are shown fine using the ratel tool.
When I try again the Graphql Query:
query MyQuery {
queryProduct {
name
}
}
none of these are returned in the graphql response.

The issue is because the dgraph also wants a DType to be passed via dql mutation like so:
models.Product{
Name: "product name",
Slug: "product-slug",
Image: "test.jpg",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
DType: []string{"Product"}, // here is the trick
}

Related

Graphql Validation

My graphql schema looks like this:
type Query {
}
type Mutation {
addEmployee(
employeePayload: EmployeeRequest!
): EmployeeResponse
}
type EmployeeResponse {
transactionId: String!
status: String!
message: String!
}
type EmploymentHistory {
historyId: Int
}
type Address {
title: String
firstLine: String!
secondLine: String!
line3: String
county: String
country: String
postcode: String
}
type Employee {
employeeId: Int!
nationalityStatus: String!
issuingOfficeName: String!
surname: String
forenames: String
dateOfBirth: String
townOfBirth: String
countryOfBirth: String
gender: String
address: Address
}
type Details {
employmentHistory: [EmploymentHistory!]
employee: Employee!
}
type Meta {
messageId: String
action: String
}
input EmployeeRequest {
details: Details
meta: Meta
}
I have a json data , which looks like this:
{
"query": "mutation addEmployee($employeePayload:EmployeeRequest!){addEmployee(employeePayload: $employeePayload) { status transactionId message} }",
"variables": {
"employeePayload": {
"meta": {
"messageId": "4fc8ec8f-67ad-46d2-9fab-1234567",
"action": "Create"
},
"details": {
"employee": {
"employeeId": 123,
"nationalityStatus": "GBR",
"issuingOfficeName": "London",
"surname": "MARRIED",
"forenames": "LEON",
"address": {
"title": "MR",
"firstLine": "20 Maze street",
"secondLine": "Darlington",
"line3": "Darlington",
"county": "UNITED KINGDOM",
"country": "UNITED KINGDOM",
"postcode": "DW1H 9EX"
},
"dateOfBirth": "1980-05-18",
"townOfBirth": "SOME PLACE",
"countryOfBirth": "UNITED KINGDOM",
"gender": "M"
},
"employmentHistory": [
{
"historyId": 123
},
{
"historyId": 456
}
]
}
}
}
}
My code to validate the json against the schema is this:
try {
String query = "mutation addEmployee($employeePayload:EmployeeRequest!)
{addEmployee(employeePayload: $employeePayload) { status
transactionId message}}";
document = parser.parseDocument(query);
} catch (ParseCancellationException e) {
log.error("There seems to be an issue parsing the document" + e.getMessage());
}
Validator validator = new Validator();
List<ValidationError> validationErrors = validator.validateDocument(schema, document);
return validationErrors.isEmpty();
The query is not the full payload (that needs to be validated). The above validation always pass. Is there a way I can find the validation constraints like not null or wrong data type?

Apollo Federation schema, representations incomplete

I have this query:
getMyTransactions {
id
createdAt
}
And I got this error:
"message": "Cannot return null for non-nullable field Transaction.createdAt.",
"path": [
"_entities",
0,
"createdAt"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"serviceName": "XXX",
"query": "query($representations:[_Any!]!){_entities(representations:$representations){...on Transaction{createdAt}}}",
"variables": {
"representations": [
{
"__typename": "Transaction",
"id": "29bf75e5-b79e-4a7d-a021-84a8b5662aa8"
},
{
"__typename": "Transaction",
"id": "616f3f8a-3c81-4d2e-bce0-03d031a15062"
}
]
},
//etc
Why isvariables.representations missing createdAt values? When I do a query directly to DynamoDB I can see createdAt values for all those 2 items.
My schemas are like this:
extend type Transaction #key(fields: "id") {
id: ID! #external
}
type Query {
getMyTransactions: [Transaction!]!
}
And the other schema has Transaction type:
type Transaction #key(fields: "id") {
id: ID!
createdAt: String!
}

AppSync graphql query not returning expected data

I have an AppSync graphql schema with Users and Events, that should have a bi-directional connection. My schema looks like this:
type User #model {
id: ID!
email: String
events: [EventUser] #connection(name: "EventUser", keyName: "byUser", fields: ["id"])
}
type Event #model {
id: ID!
name: String
description: String
registeredUsers: [EventUser] #connection(name: "EventUser", keyName: "byEvent", fields: ["id"])
invitedUsers: [User]
}
type EventUser
#model(queries: null)
#key(name: "byEvent", fields: ["eventId", "userId"])
#key(name: "byUser", fields: ["userId", "eventId"]) {
id: ID!
eventId: ID!
userId: ID!
event: Event! #connection(fields: ["eventId"])
user: User! #connection(fields: ["userId"])
}
The query that is generated by the CLI looks like this:
export const listEvents = /* GraphQL */ `
query ListEvents(
$filter: ModelEventFilterInput
$limit: Int
$nextToken: String
) {
listEvents(filter: $filter, limit: $limit, nextToken: $nextToken) {
items {
id
name
description
registeredUsers {
nextToken
}
createdAt
updatedAt
}
nextToken
}
}
`;
When I run this query with:
const result = await API.graphql(graphqlOperation(queries.listEvents, { limit: 10}))
I get these results:
[
{
"createdAt": "2020-08-17T21:36:04.502Z",
"description": "Event description",
"id": "some-unique-id",
"name": "Event name",
"registeredUsers": Object {
"nextToken": null,
},
"updatedAt": "2020-08-17T21:36:04.502Z",
},
{
"createdAt": "2020-08-17T21:36:04.502Z",
"id": "some-other-unique-id",
"name": "event 2 name",
"registeredUsers": Object {
"nextToken": null, // <- This seems wrong.
},
"updatedAt": "2020-08-17T21:36:04.502Z"
}
]
The registeredUsers field should be an array of items. I can run a query in the AppSync console like this:
query ListEvents {
listEvents( limit: 10) {
items {
id
name
registeredUsers {
items {
userId
}
}
}
}
}
and it returns correct results:
{
"data": {
"listEvents": {
"items": [
{
"id": "some-unique-id",
"name": "event name",
"registeredUsers": {
"items": [
{
"userId": "user"
},
{
"userId": "user1"
}
]
}
},
{
"id": "some-other-unique-id",
"name": "event 2 name",
"registeredUsers": {
"items": []
}
},
]
}
}
}
Obviously, the console query is slightly different but it produces correct results, although it does not handle nextToken pagination.
My question is this: Is the CLI-generated query invalid? If so, is it because my Schema is not set up correctly?
If the generated query is valid, how would I call it to get the EventUser data?

Unable to do a mutation with a property of type "array of objects" in apollo

I'm new to all graphql world, so this might be a very easy question, sorry
I'm using graphql-compose-mongoose to generate my graphql schema, here's my mongoose schema:
const ComplainSchema = new Schema({
entityId: {type: String, required: true},
user: {type: UserInfoSchema, required: true},
title: String, // standard types
desc: String,
state: {required: true, type: String, enum: ["DRAFT", "MODERATION", "PUBLIC", "SOLVED"]},
attachments: [{
url: {type: String, required: true},
name: String,
mimeType: String,
attachmentId: Schema.Types.ObjectId
}],
createdAt: {type: Date, index: true},
updatedAt: {type: Date, index: true},
}, {timestamps: {}})
export default mongoose.model('Complaint', ComplainSchema)
If I attempt the following mutation in graphiql it works fine
mutation {
complaintUpdateById(record:{_id:"5bdd9350fe144227042e6a20", title:"ok", desc:"updated", attachments:[{name:"zied", url:"http://zied.com"}]}){
recordId,
record{
_id,
entityId,
user {
userId,
userName,
roleInShop
},
title,
desc,
createdAt,
updatedAt,
attachments{
name,
url
}
}
}
}
and returns this (in case there could be helpful to see the response)
{
"data": {
"complaintUpdateById": {
"recordId": "5bdd9350fe144227042e6a20",
"record": {
"_id": "5bdd9350fe144227042e6a20",
"entityId": "5bd9b1858788f51f44ab678a",
"user": {
"userId": "5bd9ac078788f51f44ab6785",
"userName": "Zied Hamdi",
"roleInShop": "ASA"
},
"title": "ok",
"desc": "updated",
"createdAt": "2018-11-03T12:23:44.565Z",
"updatedAt": "2018-11-05T09:02:51.494Z",
"attachments": [
{
"name": "zied",
"url": "http://zied.com"
}
]
}
}
}
}
Now if I try to pass the attachments to apollo, I don't know how to do that, I don't know which type to provide (Attachment is not the right type obvisouly):
const UPDATE_COMPLAINT = gql `mutation complaintUpdateById($_id:MongoID!, $title: String!, $desc: String!, $attachments: [Attachment]
)
{
complaintUpdateById(record:{_id:$_id, title:$title, desc:$desc, attachments:$attachments}){
recordId,
record{
_id,
entityId,
user {
userId,
userName,
roleInShop
},
title,
desc,
createdAt,
updatedAt
}
}
}`
So searching for the right type, I did a introspection of my object, the issue is that I get the type of attachment as null for this query:
{
__type(name: "Complaint") {
kind
name
fields {
name
description
type {
name
}
}
}
}
this is the response:
{
"data": {
"__type": {
"kind": "OBJECT",
"name": "Complaint",
"fields": [
{
"name": "entityId",
"description": null,
"type": {
"name": "String"
}
},
{
"name": "user",
"description": null,
"type": {
"name": "ComplaintUser"
}
},
{
"name": "title",
"description": null,
"type": {
"name": "String"
}
},
{
"name": "desc",
"description": null,
"type": {
"name": "String"
}
},
{
"name": "state",
"description": null,
"type": {
"name": "EnumComplaintState"
}
},
{
"name": "attachments",
"description": null,
"type": {
"name": null
}
},
{
"name": "createdAt",
"description": null,
"type": {
"name": "Date"
}
},
{
"name": "updatedAt",
"description": null,
"type": {
"name": "Date"
}
},
{
"name": "_id",
"description": null,
"type": {
"name": null
}
}
]
}
}
}
googling didn't help since I don't know how is this operation called, I don't think it's a nested mutation from what I found...
Ok fixed,
I did these steps:
I first introspected the type of attachment in a regular query using the __typename keyword: as follows
mutation {
complaintUpdateById(record:{_id:"5bdd9350fe144227042e6a20", title:"ok", desc:"updated", attachments:[{name:"zied", url:"http://zied.com"}]}){
recordId,
record{
_id,
entityId,
user {
userId,
userName,
roleInShop
},
title,
desc,
createdAt,
updatedAt,
attachments{
__typename,
name,
url
}
}
}
}
it showed up a type named ComplaintAttachments
when replacing the Attachment type with this new value, ComplaintAttachments, an error occured and that error message helped me out:
Variable "$attachments" of type "[ComplaintAttachments]" used in
position expecting type "[ComplaintComplaintAttachmentsInput]"
so the array is of type ComplaintComplaintAttachmentsInput, I still don't know how to introspect it directly, but I'm already happy with the result :)

graphql - combining results from multiple queries into one array

I am using graphQL to perform a search across multiple mongoDB collections and API's by combining queries. All queries return a result type of
{
_id: string;
name: string;
type: string;
}
Is there any way to flatten the data into a single array?
Combined query example:
query searchAll {
books(input: {text: "e"}) {
_id
name
type
}
magazines(input: {text: "e"}) {
_id
name
type
}
}
Response currently looks like:
{"data": {
"books": [
{
"_id": "5a8ac759c25b7235ffdc6888",
"name": "someBook",
"type": "book"
}
],
"magazines": [
{
"_id": "5a87005bc25b7235ffdc4bdf",
"name": "someMagazine-1",
"type": "magazine"
},
{
"_id": "5a870067c25b7235ffdc4be4",
"name": "someMagazine-2",
"type": "client"
}
]
}
}
Desired response:
{"data": {
"results": [
{
"_id": "5a8ac759c25b7235ffdc6888",
"name": "someBook",
"type": "book"
},
{
"_id": "5a87005bc25b7235ffdc4bdf",
"name": "someMagazine-1",
"type": "magazine"
},
{
"_id": "5a870067c25b7235ffdc4be4",
"name": "someMagazine-2",
"type": "client"
}
]
}
}
You want to look into using interfaces, here's an example of a (slightly richer) schema definition:
interface Searchable {
id: ID!
name: String!
}
type Book implements Searchable {
id: ID!
name: String!
author: Author!
publisher: Publisher!
isbn: String!
}
type Magazine implements Searchable {
id: ID!
name: String!
publisher: Publisher!
issn: String!
}
input SearchInput {
text: String!
}
type Query {
search(input: SearchInput!): [Searchable!]!
}
Here's how you'd query it:
query searchAll {
search(input: {text: "e"}) {
__typename
id
name
... on Book {
author
isbn
}
... on Magazine {
issn
}
}
}
The resolver for search would be responsible for calling all the different collections and aggregating the results into a single array. Going into more depth than this is implementation-specific, but there should be docs for using interfaces (and unions, which are similar) in whichever GraphQL implementation you're using.
The __typename field is what tells you the concrete type of the returned object, thereby letting front-end code do the appropriate display logic.

Resources