We can extend the previous tutorial lesson, to duplicate multiple posts with a single GraphQL request.
For this GraphQL query to work, the Schema Configuration applied to the endpoint needs to have the following configuration:
In block Payload Types for Mutations , select "Do not use Payload Types for Mutations (i.e. return the mutated entity)" (so that dynamic variable $createdPostIDs
will contain the IDs of the created posts)
In block Mutation Scheme , select any of the two "Enable Nested Mutations" options (as to use field _echo
inside a mutation
)
This GraphQL query duplicates the posts retrieved via the provided $limit
and $offset
variables:
query InitializeDynamicVariables
@configureWarningsOnExportingDuplicateVariable ( enabled : false )
{
postInput : _echo ( value : [])
@export ( as : "postInput" )
@remove
}
query GetPostsAndExportData ( $limit : Int! = 5 , $offset : Int! = 0 )
@depends ( on : "InitializeDynamicVariables" )
{
postsToDuplicate : posts (
pagination : {
limit : $limit
offset : $offset
}
sort : {
by : ID ,
order : ASC
}
) {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author {
id
}
categories {
id
}
rawContent
excerpt
featuredImage {
id
}
tags {
id
}
title
# Already create (and export) the inputs for the mutation
postInput : _echo ( value : {
status : draft ,
authorBy : {
id : $__author
},
categoriesBy : {
ids : $__categories
},
contentAs : {
html : $__rawContent
},
excerpt : $__excerpt
featuredImageBy : {
id : $__featuredImage
},
tagsBy : {
ids : $__tags
},
title : $__title
})
@export ( as : "postInput" , type : LIST )
@remove
}
}
mutation DuplicatePosts
@depends ( on : "GetPostsAndExportData" )
{
createdPostIDs : _echo ( value : $postInput )
@underEachArrayItem (
passValueOnwardsAs : "input"
)
@applyField (
name : "createPost"
arguments : {
input : $input
},
setResultInResponse : true
)
@export ( as : "createdPostIDs" )
}
query RetrieveCreatedPosts
@depends ( on : "DuplicatePosts" )
{
createdPosts : posts (
filter : {
ids : $createdPostIDs ,
status : [ draft ]
}
) {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author {
id
}
categories {
id
}
rawContent
excerpt
featuredImage {
id
}
tags {
id
}
title
}
}
Copy
Below is the detailed analysis of how the query works.
The previous lesson employs the following strategy (on the GraphQL query of the second approach):
Export the resource IDs from the fields (including connection fields):
query GetPostAndExportData {
post {
author @export ( as : "authorID" ) {
id
}
categories @export ( as : "categoryIDs" ) {
id
}
rawContent @export ( as : "rawContent" )
rawExcerpt @export ( as : "excerpt" )
featuredImage @export ( as : "featuredImageID" ) {
id
}
tags @export ( as : "tagIDs" ) {
id
}
rawTitle @export ( as : "title" )
}
}
Copy
Create the input object for createPost(input:)
from those dynamic variables:
mutation DuplicatePost
@depends ( on : "GetPostAndExportData" )
{
createPost ( input : {
status : draft ,
authorBy : {
id : $authorID
},
categoriesBy : {
ids : $categoryIDs
},
contentAs : {
html : $rawContent
},
excerpt : $excerpt
featuredImageBy : {
id : $featuredImageID
},
tagsBy : {
ids : $tagIDs
},
title : $title
}) {
# ...
}
}
Copy
Thanks to the Field to Input extension, we can create the input object already on the first operation, and export all the required post data under a single dynamic variable:
query GetPostAndExportData {
post {
author {
id
}
categories {
id
}
rawContent
excerpt
featuredImage {
id
}
tags {
id
}
title
postInput : _echo ( value : {
status : draft ,
authorBy : {
id : $__author
},
categoriesBy : {
ids : $__categories
},
contentAs : {
html : $__rawContent
},
excerpt : $__excerpt
featuredImageBy : {
id : $__featuredImage
},
tagsBy : {
ids : $__tags
},
title : $__title
})
@export ( as : "postInput" )
}
}
Copy
Then, in the following mutation, createPost(input:)
directly receives dynamic variable $postInput
:
mutation DuplicatePost
@depends ( on : "GetPostAndExportData" )
{
createPost ( input : $postInput ) {
# ...
}
}
Copy
We must convert the query to retrieve the multiple posts to be duplicated:
Query the posts via posts(pagination: { limit : $limit, offset: $offset}) { ... }
Export postInput
as a list (i.e. an array containing all the inputs for the queried posts)
query GetPostsAndExportData ( $limit : Int! = 5 , $offset : Int! = 0 )
@depends ( on : "InitializeDynamicVariables" )
{
postsToDuplicate : posts (
pagination : {
limit : $limit
offset : $offset
}
sort : {
by : ID ,
order : ASC
}
) {
# ...
postInput : _echo ( value : {
# ...
})
@export (
as : "postInput" ,
type : LIST
)
}
}
Copy
Dynamic variable $postInput
by now contains an array with all the input data for each of the posts to duplicate:
[
{
"status" : "draft" ,
"authorBy" : {
"id" : "2"
},
"categoryIDs" : [
1
],
"contentAs" : {
"html" : "<!-- wp:paragraph --> \n <p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!</p> \n <!-- /wp:paragraph -->"
},
"excerpt" : "Welcome to WordPress. This is your first post. Edit or delete it, then start writing!" ,
"featuredImageBy" : {
"id" : null
},
"tagsBy" : {
"ids" : []
},
"title" : "Hello world!"
},
{
"status" : "draft" ,
"authorBy" : {
"id" : "3"
},
"categoryIDs" : [
3
],
"contentAs" : {
"html" : "<!-- wp:paragraph --> \n <p>This is a paragraph block. Professionally productize highly efficient results with world-class core competencies. Objectively matrix leveraged architectures vis-a-vis error-free applications. Completely maximize customized portals via fully researched metrics. Enthusiastically generate premier action items through web-enabled e-markets. Efficiently parallel task holistic intellectual capital and client-centric markets.<br><br></p> \n <!-- /wp:paragraph --> \n\n <!-- wp:heading --> \n <h2>Image Block (Standard)</h2> \n <!-- /wp:heading --> \n\n <!-- wp:image { \" id \" :1755} --> \n <figure class= \" wp-block-image \" ><img src= \" https://d.pr/i/8pTmgY+ \" alt= \"\" class= \" wp-image-1755 \" /></figure> \n <!-- /wp:image -->"
},
"excerpt" : "This is a paragraph block. Professionally productize highly efficient results with world-class core competencies. Objectively matrix leveraged architectures vis-a-vis error-free applications. Completely maximize customized portals via fully researched metrics. Enthusiastically generate premier action items through web-enabled e-markets. Efficiently parallel task holistic intellectual capital and client-centric markets. Image Block (Standard)" ,
"featuredImageBy" : {
"id" : 361
},
"tagsBy" : {
"ids" : [
11 ,
10
]
},
"title" : "Released v0.6, check it out"
}
]
Copy
In the Gato GraphQL schema, there is no mutation to create multiple posts:
Mutation createPost
receives a single input
object, not an array of them
There is no mutation createPosts
The solution is to use extensions:
@underEachArrayItem
is a composable directive (or "meta directive", it is a directive which can contain nested directives) that iterates over an array of elements, and applies its nested directive on each of them.
@underEachArrayItem
helps bridge GraphQL types, as it can make a field that returns a [String]
value, be applied a directive that receives a String
value as input (or other combinations).
For instance, in the query below:
Field User.capabilities
returns [String]
Directive @strUpperCase
receives String
Thanks to @underEachArrayItem
, we can convert all capability items to upper case:
{
user ( by : { id : 3 }) {
capabilities
@underEachArrayItem
@strUpperCase
}
}
Copy ...producing:
{
"data" : {
"user" : {
"capabilities" : [
"LEVEL_0" ,
"READ" ,
"READ_PRIVATE_EVENTS" ,
"READ_PRIVATE_LOCATIONS"
]
}
}
}
Copy
This GraphQL query passes iterates all items in $postInput
, assigns each of them to dynamic variable $input
, injects into the createPost
mutation, and finally exports the IDs of the created posts under dynamic variable $createdPostIDs
:
mutation DuplicatePosts
@depends ( on : "GetPostsAndExportData" )
{
createdPostIDs : _echo ( value : $postInput )
@underEachArrayItem (
passValueOnwardsAs : "input"
)
@applyField (
name : "createPost"
arguments : {
input : $input
},
setResultInResponse : true
)
@export ( as : "createdPostIDs" )
}
Copy
Finally, we can use dynamic variable $createdPostIDs
to retrieve the data for the newly-created posts:
query RetrieveCreatedPosts
@depends ( on : "DuplicatePosts" )
{
createdPosts : posts (
filter : {
ids : $createdPostIDs ,
status : [ draft ]
}
) {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author {
id
}
categories {
id
}
rawContent
excerpt
featuredImage {
id
}
tags {
id
}
title
}
}
Copy
The final step is to remove all fields that are auxiliary (and as such we don't need to print their output in the response) via @remove
.
The consolidated GraphQL query is:
query InitializeDynamicVariables
@configureWarningsOnExportingDuplicateVariable ( enabled : false )
{
postInput : _echo ( value : [])
@export ( as : "postInput" )
@remove
}
query GetPostsAndExportData ( $limit : Int! = 5 , $offset : Int! = 0 )
@depends ( on : "InitializeDynamicVariables" )
{
postsToDuplicate : posts (
pagination : {
limit : $limit
offset : $offset
}
sort : {
by : ID ,
order : ASC
}
) {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author {
id
}
categories {
id
}
rawContent
excerpt
featuredImage {
id
}
tags {
id
}
title
# Already create (and export) the inputs for the mutation
postInput : _echo ( value : {
status : draft ,
authorBy : {
id : $__author
},
categoriesBy : {
ids : $__categories
},
contentAs : {
html : $__rawContent
},
excerpt : $__excerpt
featuredImageBy : {
id : $__featuredImage
},
tagsBy : {
ids : $__tags
},
title : $__title
})
@export ( as : "postInput" , type : LIST )
@remove
}
}
mutation DuplicatePosts
@depends ( on : "GetPostsAndExportData" )
{
createdPostIDs : _echo ( value : $postInput )
@underEachArrayItem (
passValueOnwardsAs : "input"
)
@applyField (
name : "createPost"
arguments : {
input : $input
},
setResultInResponse : true
)
@export ( as : "createdPostIDs" )
}
query RetrieveCreatedPosts
@depends ( on : "DuplicatePosts" )
{
createdPosts : posts (
filter : {
ids : $createdPostIDs ,
status : [ draft ]
}
) {
# Fields not to be duplicated
id
slug
date
status
# Fields to be duplicated
author {
id
}
categories {
id
}
rawContent
excerpt
featuredImage {
id
}
tags {
id
}
title
}
}
Copy