GraphQL queries must be strings - express

I am writing a data fetching service on an Express backend. It needs to fetch data from a graphQL endpoint.
I get the following error. I know it's descriptive of the issue but I don't understand it.
'GraphQL queries must be strings. It looks like you\\'re sending the internal graphql-js representation of a parsed query in your request instead of a request in the GraphQL query language. You can convert an AST to a string using the `print` function
from `graphql`, or use a client like `apollo-client` which converts the internal representation to a string for you.' }
This is the function I am using:
fetchMultipleProducts(first : Number, offset : number){
fetch({
query: gql`
query {
getProduct(query: {}, first : ${first}, offset : ${offset}) {
id
code
}
}
`
})
.then(res => {
Logger.info("Fetched data");
console.log(res);
return res;
})
.catch(err => {
Logger.error("Failed to fetch", err);
});
I am trying to pass in variables into it, I assume that's allowed? And using the Gql tag is standard?
Some help would be appreciated, thanks guys.

I removed the Gql tag and sent a string as instructed in the error message. Apologies for my silliness.

Related

Need my server to return a response that includes a data error. Need client to see what was wrong with data in request

As it will become quickly apparent, I have never seriously written a webserver before
Here is the current scenario:
Clients make requests to webserver, asking to save some data
Server looks at payload, and makes 2 checks
a. Is this client banned from saving data?
b. Does the payload of this data pass a language filter?
Server responds with success, or one of those 2 errors
My endpoint is written with Express in TypeScript
class ChatRequest {
public uid: string;
public message: string;
}
export const register = (app: express.Application, deps: dependencies.IDependencies) => {
app.post("/sendChat", (req: express.Request, res: express.Response) => {
transformAndValidate(ChatRequest, req.body)
.then((sendGlobalChatRequest: SendGlobalChatRequest) => {
const payload = {
message: sendGlobalChatRequest.message,
uid: sendGlobalChatRequest.uid
};
//Check if uid is banned here
//Check if payload passes language filter here
//Save Payload here
res.sendStatus(200);
}, (err) => {
deps.logger.error(err);
res.sendStatus(503);
});
});
I have been using this article for reference:
https://hackernoon.com/the-request-sent-bad-data-whats-the-response-94088bd290a
But I think my conclusion is that they are discussing something slightly different.
So from my understanding, I can just make up HTTP codes...
so I could just do res.sendStatus(499); if the uid is banned, and maybe res.sendStatus(498); if the payload doesn't pass language filter
Then my client can just read the Int statusCode and quickly determine the failure.
But even though I think I can do that, and it would work, it doesn't seem right?
Should I instead be using a standard HTTP Response Code? https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
And then add in the body of the response, a String or something that my client can parse to determine the error?
The String parsing seems way harder to maintain, but technically seems more "legal" if that makes sense?
What is the best way for me to have a client determine the type of server-side error?
I decided to return 400 with a JSON mapping errors to bools
if (isProfane(message)) {
res.status(400).json({messageContentBlocked: true});
}
In this way the client can receive multiple errors for the request at once, and it's more explicit
And in case anyone is googling around, I am using RxSwift/RxCocoa
Here is how I handle the error on the client:
extension Error {
var chatMessageBlockedURLError: Bool {
guard let rxCocoaURLError = self as? RxCocoaURLError else {return false}
switch rxCocoaURLError {
case let .httpRequestFailed(response, data):
guard response.statusCode == 400, let data = data else {return false}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .millisecondsSince1970
guard let errors = try? decoder.decode([String:Bool].self, from: data) else {return false}
return errors["messageContentBlocked"] == true
default:
return false
}
}
}

Unable to make a sequential service (HTTP) calls in Angular 5 by using Joins

I had a Array with N number of objects. I want to make a service call sequentially. One response comes based on that i will make a another request. Please provide a better approach to handle this scenario through JOINS in Angular 5.
You can use switchMap for this.
nestedCalls(user: any) {
return this.http.get('YOUR_URL').pipe(
switchMap(data => {
const body = {
// do your work woth data - first service object
};
return this.http.post('YOUR_URL', body);
})
)
}
Or you can do something like below also :
this.service.getData(id, (response) => {
this.service.getInitiatedEntity(response.id).subscribe(
(retData) => {
// response - 1st service data
// retData - 2nd service data
}
);
});
Hope this help.

Create - How to handle empty response

My API doesn't return any response in body on POST,PATCH, etc for some resources.
How are we supposed to handle this case in data provider ?
I tried to return an empty data object but unfortunately I get the error :
"The response to 'CREATE' must be like { data: ... }, but the received response does not have a 'data' key. The dataProvider is probably wrong for 'CREATE'."
I don't know how your dataProvider looks like or what the response of your API for POST/PUT requests is, but the problem is probably located in your dataProvider's convertHTTPResponseToREST as this is responsible for handling your API's responses.
Try the following:
case CREATE:
return { data: { ...params.data, id: json.id } };
If this doesn't work either, then try this one:
case CREATE:
return { data: json };

Converge API Error Code 4000

I am attempting to POST to the Converge Demo API and I am getting a 4000 error. Message is "The VirtualMerchant ID was not supplied in the authorization request."
I am using axios inside Vuex. I am attempting to make the post from Vuex for now since it's demo. I am throwing it up https with TLSv1.2_2018.
Here's the simplified version of the code I am using.
let orderDetails = {
ssl_merchant_id:'******',
ssl_user_id:'***********',
ssl_pin: '****...',
ssl_transaction_type: 'ccsale',
ssl_amount: '5.47',
ssl_card_number: '4124939999999990',
ssl_cvv2cvc2: '123',
ssl_exp_date: '1219',
ssl_first_name: 'No Named Man',
ssl_test_mode: true
}
let orderJSON = JSON.stringify(orderDetails)
let config = {
headers: {
'Access-Control-Allow-Methods': 'PUT, POST, PATCH, DELETE, GET',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
axios.post('https://api.demo.convergepay.com/VirtualMerchantDemo/process.do', orderJSON, config)
.then(res => {
console.log('res', res.data)
})
.catch(e => {
console.log('e', e)
})
Has anyone solved this and/or able to share some wisdom?
I think you are sending the values the wrong way and that's why you receive the message of a missing parameter. The endpoing process.do expects to receive a key value pairs formatted request
ssl_merchant_id=******&ssl_user_id=***********&ssl_pin=****&ssl_transaction_type=ccsale&ssl_amount=5.47&ssl_card_number=4124939999999990&ssl_cvv2cvc2=123&ssl_exp_date=1219&ssl_first_name=No Named Man&ssl_test_mode=true
From Converge website (https://developer.elavon.com)
Converge currently supports two different ways to integrate:
Key value pairs formatted request using process.do (for a single transaction) or processBatch.do (for a batch file) with the following
syntax: ssl_name_of_field = value of field (example: ssl_amount =
1.00)
Or
XML formatted request using processxml.do (for a single transaction) or accountxml.do (for a Admin request), the transaction
data formatted in XML syntax must include all supported transaction
elements nested between one beginning and ending element , the
data is contained within the xmldata variable.

Angular multiple rest api request

im new on Angular and have a question.
I need to call 2 API Rest, on second API i need result of first API.
I have this code:
ngOnInit() {
this.Jarwis.getmyinfo()
.subscribe(
// data => console.log(data),
data => this.Getmyinfo = data,
error => console.log(error),
);
this.Jarwis.showazienda(id_azienda).subscribe(
// data => console.log(data),
data => this.Showazienda = data,
error => console.log(error),
);
}
This is a call to API rest in Jarwis:
getmyinfo(): Observable {
return this.http.get(${this.baseUrl}/me);
}
showazienda(data): Observable {
return this.http.get(${this.baseUrl}/showazienda/ + data);
}
getmyinfo is first HTTP REQUEST and where i need to get id_azienda for second HTTP REQUEST (showazienda)
I think need map result of first http request in json and get result of id_azienda but im not able to do it.
If i set 1 in the parameters of showazienda im able to get and show info of API.
For observables, you use the ".flatMap" to chain multiple async actions together (this is very similar to the promises ".then"). The flatMap allows you to used to chain multiple async requests together and have them execute one by one in order.
Here is a good explanation of flatMap.
So for your example, you would do something like this:
ngOnInit() {
this.Jarwis.getmyinfo()
.flatMap(
(data) => {
this.Getmyinfo = data;
// get id_azienda from data
return this.Jarwis.showazienda(id_azienda);
}
).subscribe(
// data => console.log(data),
data => this.Showazienda = data,
error => console.log(error),
);
}
This example code will first send the "getmyinfo()" request. Once the response is received the ".flatMap" will be called with the data received from "getmyinfo()". You can then used this data to get the "id_azienda". Then you can make the second request to "showazienda". The observable returned from "showazienda()" needs to be returned in the flatMap. Then you subscribe to the modified observable and the data you receive will be the result from the "showazienda()" request.