running a graphql mutation & query at the same time, via postman, or in general? - graphql

I'm trying to extract some metadata reliably from graphql requests from my loggigng module, but to do this I'm trying to test some more advanced scenarios.
I've tried a lot of variations of the following, some of them with the help of chatGPT (which was hilariously useless):
mutation signup{
sign1: signUp (SignUpInput: {name: "potato"}) {
id
email
phone
createdAt
}
sign2: signUp (SignUpInput: {name: "potato"}) {
id
email
phone
createdAt
}
}
query health{
health: userGraphHealth
}
unfortunately I keep getting Must provide operation name if query contains multiple operations. error.
Is it not possible/not a pattern at all, to run mutations and queries in the same document/operation?
Or is this simply a postman limitation?
EDIT: I have re-added the postman tag because this is a caveat around how postman works with graphql.

Related

How to run a query with Apollo GraphQL?

I am trying to figure out how to write a query in Apollo GraphQL.
I have a schema and have run the application in development mode. I have authenticated through the front end.
I expect that I should be able to follow this documentation and query the user.
I can see from the studio, that the Me query should be capable of checking for my first name (which I can see is recorded in the database), but when I press run in Apollo Studio, I get a null response to the query.
Is there an assumed step to get this working that needs to be taken before queries can be run? It gets worse when I try to do a query on the users table generally. That returns a not authenticated error (I have authenticated in the local environment in the dev app).
I'm struggling to connect the dots between the documentation that shows how this is expected to run queries and the starting point. I suspect that these documents have been prepared with the expectation that users know something fundamental about how to engage with them. I'm looking for disclosure as to what those assumptions might be. I can see from this question that there is a need for an authorisation header, (although my error is to do with authentication rather than authorisation). However, in my studio, the headers tab is empty. How do I populate it and what do I use to populate it?
I can see from the Apollo dev tool that it is trying to use a logged in query. I don't understand what drives this query in the Apollo Studio. Inside the localhost web app (which is running), I am logged in. When I try and run that query in the dev tools, the isLoggedIn (name of the query) is underlined, with an error explanation appearing that says:
Cannot query field "isLoggedIn" on type "Query".
The response shows:
{
"data": {}
}
I am lost for a starting point to find something to try and solve.
I think, based on a comment in this Odyssey tutorial, that the sandbox does not know how to connect to my psql data (not sure about this, but how could it know what queries I have, and not know which data has been stored in the attributes on the schema?). My env variables include my psql attributes and my prisma migrate is up to date. How can I let the sandbox know where the data is stored?
I am trying to learn using this boilerplate repo.
For my next attempt, I tried using the login mutation to generate a token, that I could try adding to the header. I don't know if it needs to be added under the name 'authorization' or 'token', so I made headers with both attribute names and added the same token to each of them.
I tried running the me and user query again, and get a mouthful of gibberish in the response.
The link in the response text goes to a page that has the following error message:
> <Error> <Code>NoSuchKey</Code> <Message>The specified key does not
> exist.</Message> </Error>
When I try going through the process of adding an APOLLO_KEY to my env variables and starting the server, I get an error that says "Unable to reach server". When I run the diagnose script on that error, I get:
Could not find any problems with the endpoint. Would you please to let
us know about this at explorer-feedback#apollographql.com 🙏
I created a new api key and tried again and am able to connect. I am able to run a login mutation and can return my first name inside that mutation, but I cannot do it from the me or user query - those queries still return the unauthenticated error response.
I have tried adding the authorization token to the header field both with and without "", and I have tried labelling that attribute as each of authorization, Authorization, token and then each of those inside "". None of them seems to make any difference to whether I can run a query. How can I find the name of the header token that Apollo Studio Explorer will accept?
I also tried the syntax suggested in this post, which is key Authorization and value "Bearer token" (there are double quotation marks around that string and a space between the word Bearer (capitalised) and the token string). There are no curly braces. That doesn't work either.
I have also tried expressing it as shown in this page of the Apollo documentation, which I think means that the key of the header value should be Authorization and the value should be the word Bearer, immediately followed by the token string generated in the output of the Login migration, inside {{ }}. When I try this, I get the same response as each of the other attempts described above.
There is a difference in the responses though, I get an unauthenticated response on the user query, and a null response on the me query.
One final strange observation: the studio returns the above error and null responses, but if I use the apollo client dev tools in the browser console, I can run the same Me query and get the result.
The user query still returns an unauthenticated error when I run it in the dev tools.
I'd also note that I can ask for the firstName attribute, inside the Login mutation, and receive them back in that response. However, I can't access them inside a Me query itself.
The next thing I investigated was how the resolver was managing the data. The boilerplate includes a resolver with:
import { AuthenticationError } from "apollo-server-express"
import { createMethodDecorator } from "type-graphql"
import { ResolverContext } from "../resolverContext"
export function UseAuth(roles?: string[]): any {
return createMethodDecorator<ResolverContext>(async ({ context: { req } }, next) => {
const argRoles = roles || []
if (req?.currentUser) {
if (argRoles.length === 0) return next()
if (argRoles.includes(req.currentUser.role)) return next()
throw new AuthenticationError("Not authorized")
} else {
throw new AuthenticationError("Not authenticated")
}
})
}
I wondered if maybe the role wasn't being considered. But I can see that it is inside the login mutation, but is not in a query.
Is there a 'for dummies' guide to getting started with apollo graphql?
I hope this spares someone some angst.
The format that works in Apollo Studio Explorer is
Key: Authorization
Value: Bearer[space][token]
There are no curly braces and no quotation marks in any of this. See this post for more discussion about this.

Can apollo server return a partial success if one element of an array is invalid?

Say I have a query that returns an array of Customer objects, each one having an id, name, and email, all of which are non-nullable. My resolver loads the data from some source, maybe a database or maybe a downstream system. Most of the data that comes back is fine, but maybe for some reason we're missing the email address for a single customer.
Currently if my resolver just returns the array of all known customers, including the dodgy one, then the entire operation will fail with something like:
{
"data": {
"customers": null
},
"errors": [{
"message": "Cannot return null for non-nullable field Customer.email"
// More error stuff here
}]
}
I get that the validation is supposed to be strict, but now on my UI it fails to load the entire list of customers just because one of them is invalid. It makes it too easy for a single record to poison the entire database.
What I would like is a way to still return the error, but to also have the data field be populated with all of the other, valid Customer records. Is this possible to do with apollo server? Or do I need to manually validate all of the data before trying to return it from my resolver? That would be quite arduous as my real data structure is much more complex.
From this discussion, it seems there's no way to do exactly what I was asking (filter out the invalid records on the server side).
The right approach to this is to either:
Make the email field nullable, so the server can return every Customer, some of which may have incomplete data; or
Make the elements of the top-level Customer array nullable, so the server can return e.g. [customer1, null, customer3]
Option 1 means that the client gets access to more data on an error, so it could still show the rest of the customer's details even if the email is missing. However it makes the data structure less reliable as now anywhere that uses the email might need to do a null check.
Option 2 is a more aggressive failure, nulling out the entire customer because of a single bad field. But it makes it simpler for the client to filter out bad customer records at the top level, allowing the rest of the frontend code to be confident that every customer has an email address.
On that basis I think I prefer option 2.
You might be interested in this article: https://blog.logrocket.com/handling-graphql-errors-like-a-champ-with-unions-and-interfaces/
It talks about using union types to report result status rather than traditional GQL error reporting. Here's an example of how it might look in your case:
type Customer {
id: ID!
name: String!
email: String!
}
interface CustomerErrorInterface {
message: String!
}
type MissingCustomerEmailError implements CustomerErrorInterface {
id: ID!
}
union CustomerResult = Customer | CustomerErrorInterface
type Query {
getCustomers: [CustomerResult!]!
}
Then, on the client side, your query would look something like this:
query getCustomers() {
__typename
... on Customer {
id
name
email
}
... on CustomerErrorInterface {
message
}
... on MissingCustomerEmailError {
id
}
}
This allows you to maintain type safety and avoid nulling things that shouldn't be nullable, while still reporting meaningful results (both successes and error types) that are associated with the data you do have. Using an error interface rather than a concrete error type in the union allows you to leave the option for reporting new types of errors in the future in a backward-compatible way.
The difference between this and the "default" GQL way of error handling (with the top-level errors output) is that reporting the error in an interface allows still giving meaningful reference data (like the id field) in easy locations rather than needing to parse error messages, and different types of errors can provide different reference data as appropriate. Error interface type handling also better fits with regular GraphQL output type patterns (in my opinion) rather than needing to switch on an enum to know how to handle different types of errors.
Allowing null in the output list may accomplish something similar in this particular case, but it makes it impossible to know which piece of data has an error, especially if the data in question does not correspond directly to a user-supplied input that can be found through the path provided by traditional error handling.

Is it possible to map a subscription parameter to an array at the mutation output?

I have a theoretical question. As I know subscription parameters must exist as a field in the returning type of the mutation. This means that the type of parameter must also match the type of the field in the returning object of the mutation. Am I right? Suppose I get an array with channels ids in the mutation response. I only send one channel id as a parameter in the subscription. Is it possible to map a subscription parameter to an array at the mutation output? If the channel id exists in the array (field channelsIds), the subscription must work. Is it possible to write this logic in the scheme itself, or is it technically impossible?
GraphQL schema:
schema {
mutation: Mutation
subscription: Subscription
}
type Mutation {
testMutation(input: TestMutationInput): TestMutationOutput
}
type TestMutationOutput {
channelsIds: [String!]!
userId: String!
userEmail: String
userPhoneNumber: String
}
type Subscription {
watchTestMutation(channelId: String!): TestMutationOutput
#aws_subscribe(mutations: ["testMutation"])
}
If I understand you correctly you want to filter based on if the mutation's returned value is in an array that is passed as an argument to the subscription. Sorry to say that is not possible at this time. Subscription filters only evaluate to true or false and cannot accommodate any logic other than that.
At the end of October 2020, I contacted AWS support for advice on this issue. I think this answer may be useful to someone, so I post their answer.
Please allow me to inform you that the use-case that you have
mentioned in the case is currently not possible via AppSync. I
understand that the lack of the feature may be causing inconvenience.
There is an internal feature request already with the AppSync team to
incorporate this feature and I have added a +1 on your behalf. It is
worth noting, that once this feature request is with the team, it will
be up to the team as to if/when this potential infrastructure feature
is implemented, and because of the limited visibility into the
progress of internal development processes, I won’t be able to provide
an ETA regarding its release. I would request you to keep an eye on
the what's new page or the AWS Blogs as all new feature requests and
enhancements are posted there[1-3].
However we can suggest a couple of workarounds in this case:
Filter the required fields on client side itself after receiving the values on the client-side from AppSync.
If the values to be filtered are very limited we can use a fake mutation made with the help of a resolver mapped to “None” Data
source. In this flow, we would create a lambda function that uses a
DynamoDB stream as the trigger. The Lambda function is triggered
whenever there's an update to the DynamoDB table.

We can then include logic in the Lambda function to filter the
required fields and perform a mutation to AppSync. In AppSync, the
mutation which was called by lambda would configured using a resolver
mapped to a “None” Data source. The None data source type passes the
request mapping template directly to the response mapping template.
And when we subscribe to this mutation, we will directly get the
filtered data from Lambda that was used to call this mutation. Please
refer to [4] for a step-by-step description of this process.
But please note that this workaround is cumbersome and would require a lot of changes if the required field values keep changing. Workaround 1(handling it on the client-side) is usually the preferred way to handle this use-case.
Resources:
[1] https://blogs.amazon.com/
[2] https://aws.amazon.com/new/
[3] https://aws.amazon.com/releasenotes/
[4] https://aws.amazon.com/premiumsupport/knowledge-center/appsync-notify-subscribers-real-time/

Verify graphql query

I'm building a simple platform using graphql as api gateway and a frontend that send some queries to this api, I'm blocked on how can I validate a query before run it to avoid malicious query to be ran. I was thinking to use persistgraphql but I just noticed that is now archived so I'm not sure if it's a good idea to use it, the second problem is that the api and the frontend are in 2 different repo so I didn't find yet a solution to whitelisting the query in the frontend and use this whitelist in the api...what's the best solution to whitelist a query with graphql?
If your concern is limiting access to certain fields based on who is making the request, then you should implement some kind of authorization strategy. You can populate the context with information about the logged in user and then use this information inside your resolvers for the fields you want to protect to determine whether the value of the field should be returned or not.
const resolvers = {
User: {
somePrivateField: (user, args, ctx) => {
// Make sure the request is from a logged in user and the user making the
// request is the same as the requested user OR the user is an admin
if (ctx.user && ( ctx.user.id === user.id || ctx.user.isAdmin )) {
return user.somePrivateField
}
// throw an error or just return null or undefined to resolve the field to
// null in the event authorization fails
}
}
}
More sophisticated strategies are possible using directives or existing libraries like graphql-shield.
Of course, certain fields that may exist on your database model -- like passwords -- should probably never be exposed in your API in the first place.

How to send graphql query by postman?

I use
POST type
URL http://######/graphql
Body:
query: "query: "{'noteTypes': {'name', 'label', 'labelColor', 'groupName', 'groupLabel', 'imageUrl'}}"
But it return
"message": "Must provide query string."
There's a better way to do it using the REST client Insomnia
Docs are here, how to send graphql queries: https://support.insomnia.rest/article/61-graphql
Below are the steps for postman
Step 1.
Run the GraphiQL in Chrome, open the Chrome Dev Console, click the Network tab, and make the query from graphiql, when you make the query, network tab will show the graphql request...
Step 2.
From the graphql request copy the request query, Select the Copy as cURL (cmd)
Step 3.
Open Postman, In the Top-Left click on the Import button, after you click Import you have to click the Paste Raw Text, and paste the copied cURL request as done in step2 after it's done click the Import
Step 4.
Postman is ready to send the Graphql request, Just Click on the Send Button, you will see the Response in the Response Box in body as below
Step 5.
To see how the query is being sent click on the Body tab next to Headers, you will get know how to provide the fields from postman in JSON format.
e.g: edges {\n node {\n id\n jobId\n }\n, If you want to view another field then you need to add it in with the suffix \n
like if need name then : edges {\n node {\n id\n jobId\n name\n }\n
\n here just means to represent a new line. Instead, you can make it simpler by providing a clear and illustrative JSON like below
===========================================================================
Note: The body type must be raw with application/json content-type. So, the query must be a valid JSON with quotes ".."
{
"query":"{viewer {user {edges {node {id jobId name }}}}}"
}
===========================================================================
you can directly start from step 5 if you know how to send the query in body and other things too that needs to be required while making a request from postman
With simplified JSON
You don't need INSOMNIA in case the GraphQL server responds to Content-type: application/graphql or postman.setEnvironmentVariable,
Just do it:
In Headers tab:
Content-Type: application/graphql
In Body tab, "raw" selected, put your query
Adding this for anyone searching on the topic ... you can utilize and test GraphQL calls far better and more easily with Insomnia:
https://insomnia.rest
It's been fantastic for GraphQL development.
There's a simple way to do it. Use a pre-request script to stringify the payload (source).
Step 1.
In the body of the request put a placeholder for the payload.
{
"query":{{query}}
}
Step 2.
Create the payload in the pre-request script and store it in an environment variable.
postman.setEnvironmentVariable("query", JSON.stringify(
`
{
search(query: "test", type: ISSUE, first: 10) {
issueCount
edges {
node {
... on Issue {
title
id
state
closed
repository {
name
}
}
}
}
}
}
`
));
That's it.
UPDATE 8-2019 - I know this is old, but regarding POSTMAN, if you haven't figured it out already, they do have a graphql (beta) option for posting body. There is no need to add any additional headers.
UPDATE 2:
It's not practical use POSTMAN, because the are working yet in a easy way to add headers, that take longtime, and i think POSTMAN is not made for work naturally with graphql,
you can follow the progress about that here:
https://github.com/postmanlabs/postman-app-support/issues/1669
I recommend to use another packages plugin like:
the best (like postman , but profile and sync price 5$ monthly):
https://insomnia.rest/
others:
https://github.com/andev-software/graphql-ide
https://github.com/imolorhe
for graphiql (no add headers possibility) you need to set three things (it's not easy to type):
Header:
Content-Type: application/json
Body:
Choose Ray < optiongroup
Choose JSON (application/json) < selectbox
Compose javascript object with "query" and the "value" of your graph query. Like all objects in js it'sneeded the propery and the value , in this case "quote" is the property, the value must be with double quotes. Inside the value (graphl string) you dont compose js objects, so you dont need use doble quotes, it's just a string.
{"query":"{ allQuotes { text } }" }
the problem is you need type all in a single line, no like grapIql... there is a post requirement in postman github so is easy work with graphql:
Postman just released inbuilt GraphQL support in version 7.2.
This version supports
Sending GraphQL queries in request body as POST requests
Support for GraphQL variables
Creating APIs in Postman with GraphQL schema type
Query autocompletion integrated with user defined GraphQL schemas
Please give it a try and give us your feedback on the tracking thread on our community forum
I faced the same problem when I try to used graphQl query using POSTMAN,
In POSTMAN send data from the raw tab with json type.
Query Command:
{"query":"{user(id:902){id,username,DOB}}"}
Mutations Command:
{ "query": "mutation {createMutations(reviewer:36, comments:\"hello\",data_id: 1659, approved: true ){id}}" }
#commnent: String Type
#data_id:Int Type
#approved:Boolean Type
If you're using Visual Studio, I have written a plugin to convert GraphQL to Restful body
https://marketplace.visualstudio.com/items?itemName=orasik.graphql-to-rest-queries
Postman has recently launched its out of box support for GraphQL: https://blog.getpostman.com/2019/06/18/postman-v7-2-supports-graphql/
Below is the screenshot of testing GraphQL locally:
Note: Running GraphQL locally using spring-boot https://www.baeldung.com/spring-graphql
Deriving from EstevĂŁo Lucas' answer.
You can also use header Content-type: application/json on postman
And define the body with:
{
"query": "{ your_query }"
}
This is easily constructed on the client side to form a request payload.
e.g.
Output:
Checkout https://github.com/hasura/graphqurl - curl for GraphQL:
CLI for making GraphQL queries with autocomplete
Run GraphiQL locally against any endpoint (with custom headers)
Use as a library with nodejs or from the browser
Supports subscriptions
I am one of the authors.
gq https://gentle-anchorage-72051.herokuapp.com/v1alpha1/graphql -i
IF we can pass header type, Then add the header Content-type: application/graphql
Below link can be used as reference:
link description here
By adding header we can run graphql query in the postman
Content-type: application/graphql

Resources