AWS AppSync: Add multiple query string items in request mapping template not work - aws-appsync

I have a request mapping template as follow: This is mapped to a GraphQL query called getPost
{
"version": "2018-05-29",
"method": "GET",
## E.G. if full path is https://api.xxxxxxxxx.com/posts then resourcePath would be /posts **
"resourcePath": "/event1/wp-json/wp/v2/posts",
"params":{
## "query":$util.toJson($ctx.args),
"query":{
"slug": "$ctx.args.slug",
"lang": "$ctx.args.lang"
},
"headers": {
"Authorization": "$ctx.request.headers.Authorization"
}
}
}
A valid JSON response URL is this:
http://my_domain/wp-json/wp/v2/posts?slug=new-post-en&lang=zh-hant
But when I tested in "Queries" using this:
query MyQuery {
getPost(slug: "new-post-en", lang: "zh-hant") {
id
}
}
No result return, but it should have at least one record returned.
Can you please tell me what's wrong with my request?
Thank you.
UPDATED Add Schema:
type Post {
id: ID!
date: String!
slug: String!
type: String!
link: AWSURL
title: AWSJSON!
content: AWSJSON!
excerpt: AWSJSON!
}
type Query {
getPost(slug: String!, lang: String): Post
getPosts: [Post]
}
schema {
query: Query
}

I found the solution:
When we make a request to http://my_domain/wp-json/wp/v2/posts?slug=new-post-en&lang=zh-hant, it will return an array in terms of JSON
However, in the schema, the query is: getPost(slug: String!, lang: String): Post
Notice the return type Post, it is not an array
So to get a valid return, we change it from
getPost(slug: String!, lang: String): Post to
getPost(slug: String!, lang: String): [Post]
And hola~ It works!

Related

GraphiQL Mutation: How can I ignore other objects in query variables

Currently having hard time setting up my end points clerk to hasura.
I am absolute new to this platform specially at GraphiQL and just following documentations and youtube video
What I am trying to do is import/insert specific data i neeed only from clerk. Here's the sample query variables:
{
"data": {
"birthday": "",
"created_at": 1654012591514,
"email_addresses": [
{
"email_address": "example#example.org",
"id": "idn_29w83yL7CwVlJXylYLxcslromF1",
"linked_to": [],
"object": "email_address",
"verification": {
"status": "verified",
"strategy": "ticket"
}
}
],
"external_accounts": [],
"external_id": "567772",
"first_name": "Example",
"gender": "",
"id": "user_29w83sxmDNGwOuEthce5gg56FcC",
"last_name": "Example",
"last_sign_in_at": 1654012591514,
"object": "user",
"password_enabled": true,
"phone_numbers": [],
"primary_email_address_id": "idn_29w83yL7CwVlJXylYLxcslromF1",
"primary_phone_number_id": null,
"primary_web3_wallet_id": null,
"private_metadata": {},
"profile_image_url": "https://www.gravatar.com/avatar?d=mp",
"public_metadata": {},
"two_factor_enabled": false,
"unsafe_metadata": {},
"updated_at": 1654012591835,
"username": null,
"web3_wallets": []
},
"object": "event",
"type": "user.created"
}
What I only need to this object is content inside of the "data" is: created_at, first_name, user_id, updated_at, profile_image_url
The GraphiQL Query I did is:
mutation CreateUser(
$created_at: String,
$first_name: String,
$user_id: String,
$updated_at: String,
$profile_image_url: String
)
{
insert_users_one(object:
{
created_at: $created_at,
first_name: $first_name,
user_id: $user_id,
updated_at: $updated_at,
profile_image_url: $profile_image_url,
}) {
created_at
first_name
user_id
updated_at
profile_image_url
}
}
Which throwing error of:
{
"errors": [
{
"extensions": {
"code": "validation-failed",
"path": "$"
},
"message": "unexpected variables in variableValues: object, type, data"
}
]
}
I tried using other method like this:
mutation CreateUser($data: users_insert_input!) {
insert_users_one(object: $data) {
created_at
first_name
user_id
updated_at
profile_image_url
}
}
But it is still having error because of object and type fields
{
"errors": [
{
"extensions": {
"code": "validation-failed",
"path": "$"
},
"message": "unexpected variables in variableValues: object, type"
}
]
}
Here's a sample of GraphQL type:
//is this how you break things down?
type Mutation {
data(
created_at: Int
first_name: String
id: String
updated_at: Int
profile_image_url: String
): Data
}
//this is what i will send in the database, things that I only need
type Verification {
status: String
strategy: String
}
type EmailAddresses {
email_address: String
id: String
object: String
verification: Verification
linked_to: [String]
}
type Data {
birthday: String
created_at: Int
external_id: String
first_name: String
gender: String
id: String
last_name: String
last_sign_in_at: Int
object: String
password_enabled: Boolean
primary_email_address_id: String
primary_phone_number_id: String
primary_web3_wallet_id: String
profile_image_url: String
two_factor_enabled: Boolean
updated_at: Int
username: String
web3_wallets: [String]
phone_numbers: [String]
external_accounts: [String]
email_addresses: [EmailAddresses]
}
type AutogeneratedMainType {
object: String
type: String
data: Data
}
I was expecting based on documents, It will ignore aren't included data.
Visit Github Discussions here
Context about the error
This is error you are receiving is based on this graphql spec - https://spec.graphql.org/June2018/#sec-Input-Objects . More over there is also a different spec for validation against variables here - https://spec.graphql.org/June2018/#sec-All-Variables-Used
TLDR; Using variable which isn’t defined in operation, will result into “unexpected variableValues” error. In your case apart from data , you have type and object as variables in your query variables object which is not defined in operation itself. Remember that query variables is an “object” expecting the variable key-values in it.
Workaround
Cleanest way to do this is to sanitize your object (which you will pass in query variables) by either creating a new object from it and passing data to it or either you remove the unnecessary fields from it which are not defined in operation. You could just delete the properties of that object. Consider yourObject containing data,type and object fields. Then you can do delete yourObject.type and delete yourObject.object. And then pass it.
This workaround is intended for client side code. But there's no exception for graphiQL explorer as that error would be thrown upon undefined variables in operation. If trying via graphiQL explorer, you would manually need to not pass those variables in query variables scope.
Conclusion
This behavior is in compliant with this graphql spec and not with Hasura directly, so we would suggest you to go through those graphql spec links and understand the aspect of it.

Spring-boot data mongoDB query nested list

I'm working on spring-boot-data-mongoDB. I have some issues querying a nested document that has a list of a specific object.
Mock class
#Document
public class Mock {
#Id
private String id;
#Indexed(unique = true)
private String name;
private List<Request> requests;
}
Request class
#Document
public class Request {
#Id
private String id;
private int status;
private String method;
private String endPoint;
private Map<String, Object> response;
private Map<String, Object> body;
private Map<String, String> params;
}
Example JSON
[
{
_id: '53fc6dde-7a534-4b37-a57e-t0bd62f50046',
name: 'mock1',
requests: [
{
status: 200,
method: 'GET',
endPoint: 'status',
response: {},
body: {},
params: {}
}
],
_class: 'com.example.mockserverspring.models.Mock'
},
{
_id: '73fc6dde-7a5b-4b37-a57e-d0bd62f50046',
name: 'tester',
requests: [
{
_id: '802220ea-a1c7-484d-af1b-86e29b540179',
status: 200,
method: 'GET',
endPoint: 'api',
response: {
data: 'GET'
},
body: {
body: 'body'
},
params: {
params: 'params'
}
},
{
_id: 'ff8673d7-01a9-4d6f-a42e-0214a56b227b',
status: 200,
method: 'GET',
endPoint: 'data',
response: {},
body: {
data: 'data'
},
params: {
value: '10'
}
},
{
_id: '7fd5a860-b415-43b0-8115-1c8e1b95c3ec',
status: 200,
method: 'GET',
endPoint: 'status',
response: {},
body: {},
params: {}
}
],
_class: 'com.example.mockserverspring.models.Mock'
}
]
Desired query output : pass in the endPoint, mockName, body, params, and method
Get the mock object of the mockName from the db.
Match endPoint, body, params, method inside the Requests List of the returned mock.
Return the response field from the request that is found matching all the above criteria.
From the above example json :
Passed in values : mockName : tester , method : GET , endPoint : api , body: {body: 'body' }, params: { params: 'params' }
This should return :
response: { data: 'GET' }
It should return if and only if all these criteria matches.
Any queries please let me know.
To perform this search the best is to use a mongoDB aggregation, inside this aggregation we will be able to execute operations step by step.
As you want to query only 1 subdocument within an array, the first operation we must perform is a $unwind of that array. This will separate each subdocument and we can perform our search.
{
"$unwind": "$requests"
}
Now we will introduce the search parameters in $match. We will be able to use as many as we want.
{
"$match": {
"name": "tester",
"requests.method": "GET",
"requests.endPoint": "api",
"requests.body": {
body: "body"
},
"requests.params": {
params: "params"
}
}
}
Finally as we only want the information of a specific field we will use $replaceRoot to format our output.
{
"$replaceRoot": {
"newRoot": "$requests.response"
}
}
Playground
EDIT:
What you trying to match by?
Generally APIs/endpoints when called via REST protocol work like this:
Request => <= Response
So I make a req and I get back a res - whether it's good or not I like it or not I get it back. Whether my params match or not.
What I can't understand is the whole design and what you're trying to match by i.e. which params? How can we match if no values exist in request LIST?
I think there are a lot of questions to be answered first. But here is some help and how I would start designing this:
Freestyle it or use Swagger to first design Req and Resp objects (schemas) - THESE ARE NOT your Requests above. These is the basic API design
Two - define what needs to happen when a request is made, with what arguments and expect what values to do the condition checking with
Define what you expect back - what fields, etc.
Define testing all of the first 3 points above individually and end to end
Then you can use each of the items in Request to test your API with. It's also fair straight forward to pull items in/out of cloud mongo service such as mongodb.com and with express easy to do the REST.

Need help to debug this updateLink resolver

I need to implement an updateLink to my graphQL server, but it keeps throwing 'id is not defined' error. The server doesn't have a database yet, only an array for practice purpose.
I have defined the schema for the mutation for update, also wrote the resolver, but it just didn't work.I have looked into the apollo document, it seems my resolver and schema are correct.
The following is the resolver
updateLink:(parent,args)=>{
const link = {
id:args.id,
description:args.description,
url:args.url,
}
links[Number(id)]=link
return link
}
},
The following the schema
type Query {
info: String!
feed: [Link!]!
link(id:ID!):Link
}
type Mutation {
post(url: String!, description: String!): Link!
updateLink(id:ID!,url:String!, description: String!): Link
delete(id:ID!):Link
}
type Link {
id: ID!
description: String!
url: String!
}
The expected outcome should be the update of the server of the link array, but I got the following error instead.
{
"data": {
"updateLink": null
},
"errors": [
{
"message": "id is not defined",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"updateLink"
]
}
]
}
You reference a variable called id here:
links[Number(id)]=link
but you have not defined a variable with that name as the error indicates. I would suggest adding a linter to your project to help you catch errors like that.

mongodb: Find elements in array field

My post schema looks like this.
const Post = new Schema({
author: String,
view: Number,
point: Number,
title: String,
images: [Schema.Types.Mixed],
content: String,
tags: [String],
comments: [{ displayName: String, body: String, createdAt: Date }],
createdAt: {
type: Date,
default: Date.now
},
editedAt: Date
})
And my query is:
Post.statics.findByTags = function(tags) {
return this.find({
tags: { $in: tags }
}).
limit(10).
sort({ createdAt: -1 }).
exec()
}
What I'm trying to do is match posts which have one of the tags provided by parameter "tags".
ex) if tags equals ["tag1", "tag2"] and
Post1 = { ...some values, tags: ["tag1"]},
Post2 = { ...some values, tags: ["tag1", "tag2"]}
I want to match both posts.
I'm using Postman to test those queries and now I'm getting nothing except an empty array.
I found mistakes that I made.
The query wasn't wrong and what I did wrong was saving "tags" field with JSON like String like "['xxx', 'xxxx']". it seems perfect array but yeah, it is just a string and I couldn't get the result I expected.
so, I added JSON.parse in "createPost" method and it now produces the right result.
// tags should be array type, so parse them
let { tags } = body
tags = JSON.parse(tags)
const { author, title, images, content } = body

Mongoose Aggregate Return to REST API - Cast to ObjectId failed for value

I am trying to set the result of my aggregate call from mongodb to a rest api endpoint. The goal is to get the count of the number of times each manager is in the collection. Below are my dependencies:
"body-parser": "^1.14.2",
"express": "^4.13.4",
"mongoose": "^4.4.2",
"nodemon": "^1.8.1",
Mongoose Schema:
var projectSchema = new Schema({
client: String,
project: String,
series: String,
manager: String,
pieceCount: Number,
dateShipped: Date,
comments: String,
items: [{description: String, barcode: Number, quantity: Number, box:
Number,returned: Boolean, dateReturned: Date}]});
Project = mongoose.model('Project', projectSchema);
Aggregate Call:
var getTotalManagers = function () {
Project.aggregate([
{ $group: {
_id: '$manager',
"total": {$sum:1}}}],
function (err, res) {
if (err) {
console.log(err);
} else {
console.log(JSON.stringify(res));
/* return (JSON.stringify(res)); (what is used when not writing to
console */
}
});
};
getTotalManagers();
This returns the desired results to the console:
[{"_id":"Fname Lname","total":1},{"_id":"Fname Lname","total":1},
{"_id":"Fname Lname","total":4},{"_id":"Fname Lname","total":2},
{"_id":"Fname Lname","total":2}]
Rest API Call:
router.get('/totals',getTotalManagers);
I get this error message when trying to access the api call:
{
"message": "Cast to ObjectId failed for value \"totals\" at path \"_id\"",
"name": "CastError",
"kind": "ObjectId",
"value": "totals",
"path": "_id"
}
What is the proper way to set this to a rest api endpoint? I feel like that is the issue since the aggregate call is working to the console. Any help would be appreciated. Thanks.