I could use some help figuring out how to handle a batch request in gqlgen. The request is coming from an apollo client using apollo's query batching, so the request body is a json array like so:
[
{
"operationName":"UpdateDocument",
"variables":{
"input":{
"document_id":"123"
}
},
"query":"mutation UpdateDocument($input: UpdateDocumentInput!) {
updateDocument(input: $input) {
document {
id
__typename
}
__typename
}
}"
},
{
"operationName":"UpdateDocument",
"variables":{
"input":{
"document_id":"124"
}
},
"query":"mutation UpdateDocument($input: UpdateDocumentInput!) {
updateDocument(input: $input) {
document {
id
__typename
}
__typename
}
}"
}
]
and in the gqlgen side, I have a resolver that handles a single UpdateDocument query.
When I am making the batch request I get an error: "json body could not be decoded: json: cannot unmarshal array into Go value of type graphql.RawParams"
Related
Actual Graphql query works fine
mutation createQuestion($data:QuestionInput!) {
createQuestion(data: $data) {
data {
id
attributes {
title
description
question_id
}
}
}
}
When client side(below code in GOLANG) ran this query it's gives an issue
CreateQuestion struct {
Data struct {
ID graphql.ID
Attributes struct {
Question_id graphql.String
Title graphql.String
Description graphql.String
}
}
}
Passing Data like this
variables := map[string]interface{} {
"data": map[string]interface{} {
"title": "My testFirst FbPost",
"description": "dfsdf is the body of my first post.",
"question_id": "35005",
},
}
Gives an Error like below
Failed to run mutation: found
non-200 OK status code: 400 Bad Request body:
"message":"Syntax Error: Expected Name",
"code":"GRAPHQL_PARSE_FAILED",
"stacktrace":"GraphQLError"
Trying to Posting data to Server(Strapi CMS) using Golang client Library.
type QuestionInput map[string]interface{}
variables := map[string]interface{}{
"data": QuestionInput {
"title": "My testFirst FbPost",
"description": "dfsdf is the body of my first post.",
"question_id": "35005",
},
}
I am using Strapi, Graphql and Nuxt.js to get a list of projects and then display a single project based on the button that is clicked which should carry along a slug of the project name in route params.
The Graphql query looks like below and does work in playground if I pass along a slug in a variable.
query GetProject($slug: String!) {
projects(where: {slug: $slug}) {
id
name
slug
}
}
Query Variables
{
"slug": "tunnel-to-new-york"
}
the result is
{
"data": {
"projects": [
{
"id": "5ea7904136a59018ac9ffb54",
"name": "Tunnel to New York",
"slug": "tunnel-to-new-york"
}
]
}
}
In the projects page the button is
<v-btn to="/projects/`${slug}`">Model + Details</v-btn>
and in the Apollo query on the projects list page
apollo: {
projects: {
prefetch: true,
query: projectsQuery,
variables() {
return { slug: this.$route.params.slug };
}
}
},
what gets sent to the address bar is
http://localhost:3000/projects/%60$%7Bslug%7D%60
if i type in the slug like
http://localhost:3000/projects/tunnel-to-new-york
the error is missing parameter - its returning an array instead of an object
the single project query is
query GetProject($slug: String!) {
projects(where: {slug: $slug}) {
id
name
slug } }
and in the _slug.vue
apollo: {
project: {
prefetch: true,
query: projectQuery,
variables () {
return { slug: this.$route.params.slug }
}
}
}
Any insights would be appreciated!
so the issue was not binding the 'to' in the button - the colon was missing and changed {slug} to {projects.slug}
<v-btn :to="`/project/${project.slug}`">Model + Details</v-btn>
thanks to Jeffery Biles https://www.youtube.com/watch?v=NS0io3Z75GI&list=PLPwpWyfm6JACZm5kqu6p4s7XHXbAQ7fP-
Receiving data with AppSync directly from DynamoDB seems working for my case, but when I try to put a lambda function in between, I receive errors that says "Can't resolve value (/issueNewMasterCard/masterCards) : type mismatch error, expected type LIST"
Looking to the AppSync cloudwatch response mapping output, I get this:
"context": {
"arguments": {
"userId": "18e946df-d3de-49a8-98b3-8b6d74dfd652"
},
"result": {
"Item": {
"masterCards": {
"L": [
{
"M": {
"cardId": {
"S": "95d67f80-b486-11e8-ba85-c3623f6847af"
},
"cardImage": {
"S": "https://s3.eu-central-1.amazonaws.com/logo.png"
},
"cardWallet": {
"S": "0xFDB17d12057b6Fe8c8c434653456435634565"
},...............
here is how I configured my response mapping template:
$utils.toJson($context.result.Item)
I'm doing this mutation:
mutation IssueNewMasterCard {
issueNewMasterCard(userId:"18e946df-d3de-49a8-98b3-8b6d74dfd652"){
masterCards {
cardId
}
}
}
and this is my schema :
type User {
userId: ID!
masterCards: [MasterCard]
}
type MasterCard {
cardId: String
}
type Mutation {
issueNewMasterCard(userId: ID!): User
}
The Lambda function:
exports.handler = (event, context, callback) => {
const userId = event.arguments.userId;
const userParam = {
Key: {
"userId":{S:userId}
},
TableName:"FidelityCardsUsers"
}
dynamoDB.getItem(userParam, function(err, data) {
if (err) {
console.log('error from DynamDB: ',err)
callback(err);
} else {
console.log('mastercards: ',JSON.stringify(data));
callback(null,data)
}
})
I think the problem is that the getItem you use when you use the DynamoDB datasource is not the same as the the DynamoDB.getItem function in the aws-sdk.
Specifically it seems like the datasource version returns an already marshalled response (that is, instead of something: { L: [ list of things ] } it just returns something: [ list of things]).
This is important, because it means that $utils.toJson($context.result.Item) in your current setup is returning { masterCards: { L: [ ... which is why you are seeing the type error- masterCards in this case is an object with a key L, rather than an array/list.
To solve this in the resolver, you can use the $util.dynamodb.toDynamoDBJson(Object) macro (https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html#dynamodb-helpers-in-util-dynamodb). i.e. your resolver should be:
$util.dynamodb.toDynamoDBJson($context.result.Item)
Alternatively you might want to look at the AWS.DynamoDB.DocumentClient class (https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html). This includes versions of getItem, etc. that automatically marshal and unmarshall the proprietary DynamoDB typing back into native JSON. (Frankly I find this much nicer to work with and use it all the time).
In that case you can keep your old resolver, because you'll be returning an object where masterCards is just a JSON array.
I don't use Relay container, because I'd like to have more control over components. Instead of it I use HOC + Relay.Store.forceFetch, that fetches any given query with variables. So I have the following query:
query {
root {
search(filter: $filter) {
selectors {
_id,
data {
title,
status
}
},
selectorGroups {
_id,
data {
title,
}
}
}
}
}
Then I have to do some mutation on selector type.
export default class ChangeStatusMutation extends Relay.Mutation {
getMutation() {
return Relay.QL`mutation {selectors_status_mutation}`;
}
getVariables() {
return {
id: this.props.id,
status: this.props.status
};
}
getFatQuery() {
return Relay.QL`
fragment on selectors_status_mutationPayload{
result {
data {
status
}
}
}
`;
}
static fragments = {
result: () => Relay.QL`
fragment on selector {
_id,
data {
title,
status
}
}`,
};
getOptimisticResponse() {
return {
result: {
_id: this.props.id,
data: {
status: this.props.status
}
}
};
}
getConfigs() {
return [{
type: 'FIELDS_CHANGE',
fieldIDs: {
result: this.props.id
},
}];
}
}
Call mutation in component:
const mutation = new ChangeStatusMutation({id, status, result: selector});
Relay.Store.commitUpdate(mutation);
After mutation commitment selector in Relay storage is not changed. I guess that's because of empty Tracked Fragment Query and mutation performs without any fields:
ChangeStatusMutation($input_0:selectors_statusInput!) {
selectors_status_mutation(input:$input_0) {
clientMutationId
}
}
But the modifying selector was already fetched by Relay, and I pass it to the mutation with props. So Relay knows the type, that should be changed, how to find the item and which fields should be replaced. But can not intersect. What's wrong?
So, you're definitely a bit "off the ranch" here by avoiding Relay container, but I think this should still work...
Relay performs the query intersection by looking up the node indicated by your FIELDS_CHANGE config. In this case, your fieldIDs points it at the result node with ID this.props.id.
Are you sure you have a node with that ID in your store? I'm noticing that in your forceFetch query you fetch some kind of alternative _id but not actually fetching id. Relay requires an id field to be present on anything that you later want to refetch or use the declarative mutation API on...
I'd start by checking the query you're sending to fetch whatever this result type is. I don't see you fetching that anywhere in your question description, so I'm just assuming that maybe you aren't fetching that right now?
I have mutation (code) in which I want to delete a node. It has a dependency on the post rowId — which is the primary key of the row in the database — and the viewer id. When the pertaining component (code) gets rendered. The following queries are sent
query Queries {
viewer {
id,
...F1
}
}
fragment F0 on Viewer {
id
}
fragment F1 on Viewer {
id,
...F0
}
and
query Queries($id_0:ID!) {
post(id:$id_0) {
id,
...F2
}
}
fragment F0 on Post {
id,
rowId
}
fragment F1 on Post {
rowId,
id
}
fragment F2 on Post {
headline,
body,
id,
...F0,
...F1
}
The response I get includes the viewer.id and post.rowId. As you can see here,
{
"data": {
"post": {
"id": "cG9zdDo0",
"headline": "You hit me with a cricket bat.",
"body": "Hello.",
"rowId": 4
}
}
}
and here,
{
"data": {
"viewer": {
"id": "viewer"
}
}
}
However when I want to pass them to the DeletePostMutation like so this.props.post.id they are undefined. When I inspect this.props.post, I get the following
The error suggests that the props passed down to DeletePostMutation is not data fetched by Relay, and looking at the code it seems you are constructing a new object for the post and the viewer as opposed to sending the post and viewer fetched by relay.
I see you are doing this:
handleDelete(event) {
this.props.relay.commitUpdate(
new DeletePostMutation({
post: { rowId: this.props.post.rowId },
viewer: { id: this.props.viewer.id },
})
)
}
Try this instead:
handleDelete(event) {
this.props.relay.commitUpdate(
new DeletePostMutation({
post: this.props.post,
viewer: this.props.viewer,
})
)
}
Since you are already composing the GraphQL fragments of DeletePostMutation inside the Post Relay Container then inside DeletePostMutation each prop should have the fields defined in the fragments accessible.