How to test and automate APIs implemented in GraphQL - graphql

In our company, we are creating an application by implementing graphQL.
I want to test and automate this APIs for CI/CD.
I have tried REST-assured but since graphQL queries are different than Json,
REST-assured doesn't have proper support for graphQL queries as discussed here.
How can we send graphQL query using REST-assured?
Please suggest the best approach to test and automate graphQL APIs
And tools which can be used for testing and automation.

So I had the same issue and I was able to make it work on a very simple way.
So I've been strugling for a while trying to make this graphQL request with Restassured in order to validate the response (amazing how scarce is the info about this) and since yesterday I was able to make it work, thought sharing here might help someone else.
What was wrong? By purely copying and pasting my Graphql request (that is not json format) on the request was not working. I kept getting error "Unexpected token t in JSON at position". So I thought it was because graphql is not JSON or some validation of restassured. That said I tried to convert the request to JSON, imported library and lot of other things but none of them worked.
My grahql query request:
String reqString = "{ trade { orders { ticker } }}\n";
How did I fixed it? By using postman to format my request. Yes, I just pasted on the QUERY window of postman and then clicked on code button on the right side (fig. 1). That allowed my to see my request on a different formatt, a formatt that works on restassured (fig. 2). PS: Just remeber to configure postman, which I've pointed with red arrows.
My grahql query request FORMATTED:
String reqString = {"query":"{ trade { orders { ticker } }}\r\n","variables":{}}
Fig 1.
Fig 2.
Hope it helps you out, take care!

You can test it with apitest
{
vars: { #describe("share variables") #client("echo")
req: {
v1: 10,
}
},
test1: { #describe("test graphql")
req: {
url: "https://api.spacex.land/graphql/",
body: {
query: `\`query {
launchesPast(limit: ${vars.req.v1}) {
mission_name
launch_date_local
launch_site {
site_name_long
}
}
}\`` #eval
}
},
res: {
body: {
data: {
launchesPast: [ #partial
{
"mission_name": "", #type
"launch_date_local": "", #type
"launch_site": {
"site_name_long": "", #type
}
}
]
}
}
}
}
}
Apitest is declarative api testing tool with JSON-like DSL.
See https://github.com/sigoden/apitest

Related

Updating meta fields in Shopify with GrapQL

I've never used GraphQL before so I am really lacking knowledge on how to go about this. I'm wanting to update product meta fields on Shopify and it appears this is the only way. What I've done so far is really fumbling...
My JSON is:
{
"input": {
"id": "gid://shopify/Product/749521178847",
"metafields": [
{
"id": "gid://shopify/Metafield/2223333",
"value": "Training Grounds"
}
]
}
}
I've minified this to:
{"input":{"id":"gid://shopify/Product/749521178847","metafields":[{"id":"gid://shopify/Metafield/2223333","value":"The Training Grounds"}]}}
And am then using an HTTP request to:
https://MYSTORE.myshopify.com/api/2021-10/graphql.json?query={"input":{"id":"gid://shopify/Product/749521178847","metafields":[{"id":"gid://shopify/Metafield/2223333","value":"The Training Grounds"}]}}
I get the error:
SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data
I don't know if any of this is correct. If it is, I don't know if ?query= is the right variable to pass it through on.
I recommend you start using Postman, thunder client, or similar to write your graphql queries first, you will learn a lot about how graphql works and the error msgs will be a lot more useful.
To easily connect with Shopify on this stage, go to a store and create a private app, now you can use this for authenticating your API calls.
After that the Shopify graphql works on POST, you can't write your request on GET mode.
It needs to be a POST and you are missing type of operation mutation in this case and what it is.
Postman has https://www.postman.com/lively-moon-541169/workspace/purego-apis/example/16545848-bf0d1589-09b1-4ec6-ba63-a65a56b500eb examples of how to do the calls which can help you.
Also you can check GraphiQL app on shopify to test all the queries before making the programmatic queries
Updating an existing metafield:
mutation {
metafieldsSet(metafields: [
{namespace: "YOURNAMESPACE", ownerId: "gid://shopify/Customer/CUSTOMER_ID", type: "single_line_text_field", key: "YOURKEY", value: "THIS IS NEW VALUE"}
]) {
metafields {
key
value
}
userErrors {
field
message
}
}
}
Creating new metafield:
mutation {
customerUpdate(input: {
id: "gid://shopify/Customer/CUSTOMER_ID",
metafields: [
{key: "newkey", value: "some value", type: "single_line_text_field", namespace: "some namespace"},
]
}) {
userErrors {
field
message
}
}
}

How can I create an issue with github GraphQL API?

I'm starting to use GraphQL API and I've seen that the mutation createIssue was recently added but I don't know how to use it. I've tried the following but I'm getting errors:
mutation {
createIssue(input:{
repositoryId:"XXXXXXXXXXXX",
assigneeIds:"XXXXXXX",
title:"TestIssue",
body:"Not able to create an issue"})
}
You need first to get the repository id using the following request:
query FindRepo {
repository(owner: "johndoe", name: "awesome-repo") {
id
}
}
Then you call the mutation request by replacing the id you've got in the response in repositoryId field :
mutation CreateIssue {
createIssue(input: {repositoryId: "[ID from previous call]", title: "TestIssue", body: "Not able to create an issue"}) {
issue {
number
body
}
}
}
You can try both call in the graphql explorer and running first the FindRepo request and then CreateIssue
Or you can do it like this:
As the previous answer said, you have to find the repositoryId first, or you will met the error in the image.
And further more, when you have any issues finding a way to do mutation or query, you can find your answer in the Doc section in the right of the github explorer.

Hasura: Allow-list configuration

I'm trying to setup the allow list feature in Hasura, but the docs seem pretty sparse. This is one of the queries:
{
hasura_auth(args: {cleartext_password: "xxx", email: "email#mail.com"}) {
jwt_token
}
}
How would I integrate the dynamic parts in an allow list?
I tried this and lot's of variations with no luck:
{
hasura_auth(args: {cleartext_password: $pass, email: $email}) {
jwt_token
}
}
Thanks for your help!
What you have to know is to tell hasura the name of your query with full syntax.
like this...
Operation name is => get_user_by_pk
Operation is
query get_user_by_pk($id: uuid!) {
user_by_pk(id: $id) {
id
username
email
}
}
the main part is you have to use the exact operation in your code having the operation name.
now, in your project, you will send the variable (in this case id[uuid]) to the query handler and send this to your hasura server.
ask me if it is not clear for you.

How to run a graphql against faunadb from html client

I am totally new to graphql and faunadb, so plz bear with me if its a silly question.
I see I can run graphql query from the dashboard > GRAPHQL. e.g. Pasting the following code
query FindAllTodos {
allTodos {
data {
_id
title
completed
list {
title
}
}
}
}
and hitting the Run button. But how I can run this query from my html/js code which I want to run in browser?
In js I can create the clientsdk but not sure how to pass the above query?
import faunadb, { query as q } from 'faunadb';
let adminClient = new faunadb.Client({
secret: 'my-key'
});
On googling I found example which were using some FQL like structures like
adminClient.query(
q.Get(q.Ref(q.Collection('Todo'), '276653641074475527'))
)
.then((ret) => console.log(ret));
but how I can just pass the graphql query and get the same result, its returning me in right side pane of the graphql play ground.
You can use a client like curl or any GraphQL client.
With curl you can issue something like:
curl -X POST -H 'Authorization: Bearer <your key>' https://graphql.fauna.com/graphql -d '{ "query": "{ FindAllTodos{ data {_id title completed list { title }} }}"}'
I can get you 90% there but the code I present to you is written in TypeScript in an Angular app that uses HttpClient and RxJs Observables. With a little effort you can rewrite in JS using vanilla HTTP fetch.
By the way here is a video by Brecht De Rooms that helped me a lot:
https://www.youtube.com/watch?v=KlUPiQaTp0I
const SERVER_KEY = 'Your server key goes here';
const executeQuery = (query: string) => {
const headers = new HttpHeaders().set('Authorization', 'Bearer ' + SERVER_KEY);
return this.http.post<any>('https://graphql.fauna.com/graphql',
JSON.stringify({ query }), { headers });
}
const findAllTodos = () => {
const query = `query FindAllTodos {
allTodos {
data {
_id
title
completed
list {
title
}
}
}
}`;
return executeQuery(query);
}
findAllTodos().subscribe(console.log);
For me the hurdle was learning that the Fauna server expects JSON in this form:
{ "query": "query FindAllTodos {allTodos { ... and so forth and so on ..." }
That same structure applies when you run a mutation:
{ "query": "mutation AddTodo { ...etc... " }
By the way, if your query doesn't work the first time, which it probably won't, I recommend opening your browser's developer's tools Network tab and inspect the request that was sent to the Fauna server. Look at the Response. There will be error information in there. The response status will be 200(OK) even when there are errors. You need to look inside the response to check for errors.

Resolve to the same object from two incoherent sources in graphql

I have a problem I don't know how to solve properly.
I'm working on a project where we use a graphql server to communicate with different apis. These apis are old and very difficult to update so we decided to use graphql to simplify our communications.
For now, two apis allow me to get user data. I know it's not coherent but sadly I can't change anything to that and I need to use the two of them for different actions. So for the sake of simplicity, I would like to abstract this from my front app, so it only asks for user data, always on the same format, no matter from which api this data comes from.
With only one api, the resolver system of graphql helped a lot. But when I access user data from a second api, I find very difficult to always send back the same object to my front page. The two apis, even though they have mostly the same data, have a different response format. So in my resolvers, according to where the data is coming from, I should do one thing or another.
Example :
API A
type User {
id: string,
communication: Communication
}
type Communication {
mail: string,
}
API B
type User {
id: string,
mail: string,
}
I've heard a bit about apollo-federation but I can't put a graphql server in front of every api of our system, so I'm kind of lost on how I can achieve transparency for my front app when data are coming from two different sources.
If anyone has already encounter the same problem or have advice on something I can do, I'm all hear :)
You need to decide what "shape" of the User type makes sense for your client app, regardless of what's being returned by the REST APIs. For this example, let's say we go with:
type User {
id: String
mail: String
}
Additionally, for the sake of this example, let's assume we have a getUser field that returns a single user. Any arguments are irrelevant to the scenario, so I'm omitting them here.
type Query {
getUser: User
}
Assuming I don't know which API to query for the user, our resolver for getUser might look something like this:
async () => {
const [userFromA, userFromB] = await Promise.all([
fetchUserFromA(),
fetchUserFromB(),
])
// transform response
if (userFromA) {
const { id, communication: { mail } } = userFromA
return {
id,
mail,
}
}
// response from B is already in the correct "shape", so just return it
if (userFromB) {
return userFromB
}
}
Alternatively, we can utilize individual field resolvers to achieve the same effect. For example:
const resolvers = {
Query: {
getUser: async () => {
const [userFromA, userFromB] = await Promise.all([
fetchUserFromA(),
fetchUserFromB(),
])
return userFromA || userFromB
},
},
User: {
mail: (user) => {
if (user.communication) {
return user.communication.mail
}
return user.mail
}
},
}
Note that you don't have to match your schema to either response from your existing REST endpoints. For example, maybe you'd like to return a User like this:
type User {
id: String
details: UserDetails
}
type UserDetails {
email: String
}
In this case, you'd just transform the response from either API to fit your schema.

Resources