-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"An operation name is required if the query contains multiple operations" #406
Comments
It looks like an error you are getting from the GraphQL API, I don't think this is an error with |
Actually, I can't pass the parameter on the body of operationName. I have queryFile has multiple operations as the following example:
So, I want to use the
|
Guys, this is regular/plain stuff: https://graphql.org/learn/serving-over-http/#post-request-and-body It is quite amazing to me that this issue has been open over 3 years and received no attention. It is quite inconvenient to be forced to put everything in separate documents because your library doesn't support @Nasr-Ladib has a perfectly valid use case here, a query is being sent that contains more than one operation. Then, according to the spec, he has to point out which operation he wants to execute in this query. This is done via Here is a scenario: Imagine having two different queries for GitHub pull requests. Both are using the same fragment but each have slightly different input filters to the root query. Our document fragment PullRequestFields on PullRequest {
# 100+ lines of fields here
}
query RepositoryPullRequestsFilteredByLabel(
$owner: String!
$name: String!
$label: String!
$batchSize: Int = 10
$cursor: String
$labelsBatchSize: Int = 5
$labelsCursor: String
) {
repository(owner: $owner, name: $name) {
pullRequests(
states: OPEN
first: $batchSize
after: $cursor
labels: [$label]
orderBy: { field: CREATED_AT, direction: DESC }
) {
nodes {
...PullRequestFields
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
query RepositoryPullRequests(
$owner: String!
$name: String!
$batchSize: Int = 10
$cursor: String
$labelsBatchSize: Int = 5
$labelsCursor: String
) {
repository(owner: $owner, name: $name) {
pullRequests(
states: OPEN
first: $batchSize
after: $cursor
orderBy: { field: CREATED_AT, direction: DESC }
) {
nodes {
...PullRequestFields
}
pageInfo {
hasNextPage
endCursor
}
}
}
} The query Here is how we want to use it: import RepositoryPullRequestsFilteredByLabel from './RepositoryPullRequestsFilteredByLabel.gql'
await graphql({
query: print(RepositoryPullRequestsFilteredByLabel), // Contains two operations + 1 fragment
operationName: 'RepositoryPullRequestsFilteredByLabel', // Point out which operation we want to use; RepositoryPullRequestsFilteredByLabel or RepositoryPullRequests
owner: ownerName,
name: repoName,
label,
batchSize,
cursor,
labelsBatchSize,
labelsCursor,
}) However the library does not support this. |
Here is a workaround:
import {
type DocumentNode,
type FragmentDefinitionNode,
Kind,
type OperationDefinitionNode,
} from 'graphql'
export function extractOperation(
doc: DocumentNode,
operationName: string,
): DocumentNode {
const operation = doc.definitions.find(
(def): def is OperationDefinitionNode =>
def.kind === Kind.OPERATION_DEFINITION &&
def.name?.value === operationName,
)
if (!operation) {
throw new Error(
`Operation "${operationName}" not found in the provided DocumentNode`,
)
}
// Collect all fragment definitions
const fragmentDefinitions = new Map<string, FragmentDefinitionNode>()
doc.definitions.forEach((def) => {
if (def.kind === Kind.FRAGMENT_DEFINITION) {
fragmentDefinitions.set(def.name.value, def)
}
})
// Find fragments that are actually used in the operation
const usedFragments = new Set<string>()
function collectUsedFragments(node: any) {
if (node.kind === Kind.FRAGMENT_SPREAD) {
if (!usedFragments.has(node.name.value)) {
usedFragments.add(node.name.value)
const fragment = fragmentDefinitions.get(node.name.value)
if (fragment) {
collectUsedFragments(fragment)
}
}
} else if (node.selectionSet) {
node.selectionSet.selections.forEach(collectUsedFragments)
}
}
collectUsedFragments(operation)
// Include only the operation and necessary fragments
return {
...doc,
definitions: [
operation,
...Array.from(usedFragments).map(
(name) => fragmentDefinitions.get(name)!,
),
],
}
} Updated example usage code: import Raw from './RepositoryPullRequestsFilteredByLabel.gql'
const RepositoryPullRequestsFilteredByLabel = extractOperation(
Raw,
'RepositoryPullRequestsFilteredByLabel',
)
const RepositoryPullRequests = extractOperation(
Raw,
'RepositoryPullRequests',
)
// ...
await graphql({
query: print(RepositoryPullRequestsFilteredByLabel), // Use the appropriate query
owner: ownerName,
name: repoName,
label,
batchSize,
cursor,
labelsBatchSize,
labelsCursor,
}) Now we can keep everything in one file and still use |
Over the last couple years there have been changes to the people working on Octokit. Previously there was gr2m that was dedicated full time working on JS Octokit. There are a few community contributors who have push access. I personally can't help, I don't know anything about GraphQL. Besides, it's not just this repo that is feeling the effects where there are issues that are a couple years old. The whole of JS Octokit is lacking attention |
@wolfy1339 Sure, I opened a PR for it! #629 And also a types PR: octokit/types.ts#662 |
🎉 This issue has been resolved in version 8.2.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Hi. I am trying to put many queries and fragments inside one request.
My POST request's body:
I found that I can add ./src/graphql.ts:11
add a non-variable option
operationName
Please give me some clues. Thanks in advance.
The text was updated successfully, but these errors were encountered: