graphql-python / gql

A GraphQL client in Python

Home Page:https://gql.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Schema not completely fetched from introspection query

Jonas1312 opened this issue · comments

Hi,

First, thanks a lot for gql!

Describe the bug
When fetching the schema from the backend, some @deprecated fields are missing.

To Reproduce
gql-cli https://preproduction.cloud.kili-technology.com/api/label/v2/graphql --print-schema > schema_preprod.graphql

The fetched schema shows this:

input OrganizationData {
  license: String
  name: String
}

while the real schema looks like this:

input OrganizationData {
  address: String @deprecated(reason: "This information is not relevant")
  city: String @deprecated(reason: "This information is not relevant")
  country: String @deprecated(reason: "This information is not relevant")
  license: String
  name: String
  zipCode: String @deprecated(reason: "This information is not relevant")
}

Expected behavior
The schema fetching method(s) should not skip deprecated fields.

System info (please complete the following information):

  • OS: macos
  • Python version: 3.7
  • gql version: v3.5.0b3
  • graphql-core version: 3.3.0a2

Thanks

I checked with the GitHub GraphQL API:

gql-cli https://api.github.com/graphql --header "Authorization: Bearer MYTOKEN" --print-schema > github_schema.txt

and deprecated fields are present in the downloaded schema.

Example:

"""Represents an 'assigned' event on any assignable object."""                                                          
type AssignedEvent implements Node {                                                                                    
  """Identifies the actor who performed the event."""                                                                   
  actor: Actor                                                                                                          
                                                                                                                        
  """Identifies the assignable associated with the event."""                                                            
  assignable: Assignable!                                                                                               
                                                                                                                        
  """Identifies the user or mannequin that was assigned."""                                                             
  assignee: Assignee                                                                                                    
                                                                                                                        
  """Identifies the date and time when the object was created."""                                                       
  createdAt: DateTime!                                                                                                  
  id: ID!                                                                                                               
                                                                                                                        
  """Identifies the user who was assigned."""                                                                           
  user: User @deprecated(reason: "Assignees can now be mannequins. Use the `assignee` field instead. Removal on 2020-01-01 UTC.")
} 

So either your backend decided to remove those deprecated fields, or for some reason they don't send them in response of an instrospection query.

Well those deprecated fields are still showing on apollo: https://studio.apollographql.com/sandbox/schema/reference/inputs/OrganizationData?query=OrganizationData (enter this endpoint: https://preproduction.cloud.kili-technology.com/api/label/v2/graphql)

They are still in the backend.

So I don't understand where they are being removed

I'll try to investigate

You can use --debug to see the answer of the server. I attached the answer received below. You can see the 106th type only contains license and name

introspection.zip

Alright, I just found out that in our introspection query, we use includeDeprecated:true for the fields and enumValues but not for the inputFields.
̶T̶h̶i̶s̶ ̶c̶o̶u̶l̶d̶ ̶b̶e̶ ̶a̶ ̶b̶u̶g̶ ̶i̶n̶ ̶g̶r̶a̶p̶h̶q̶l̶-̶c̶o̶r̶e̶.̶
Investigating further...

graphql-core added support for deprecated input values on 2021-08-06 in this commit but by default it was not enabled.

The prototype for get_introspection_query is:

def get_introspection_query(                                                                                            
    descriptions: bool = True,                                                                                          
    specified_by_url: bool = False,                                                                                     
    directive_is_repeatable: bool = False,                                                                              
    schema_description: bool = False,                                                                                   
    input_value_deprecation: bool = False,                                                                              
) -> str:                                                                                                               
    """Get a query for introspection.

In gql, to get the introspection query, we're just calling get_introspection_query() without arguments so we don't get deprecated input values.

Ah I see, thanks for investigating!

As a workaround, you can get the complete schema by running:

import asyncio                                                                                                          
                                                                                                                        
from gql import Client, gql                                                                                             
from gql.transport.aiohttp import AIOHTTPTransport                                                                      
from graphql import get_introspection_query, print_schema, parse, build_client_schema                                   
                                                                                                                        
                                                                                                                        
async def main() -> int:                                                                                                
                                                                                                                        
    transport = AIOHTTPTransport(                                                                                       
        url="https://preproduction.cloud.kili-technology.com/api/label/v2/graphql"                                      
    )                                                                                                                   
                                                                                                                        
    # Connect to the backend and provide a session                                                                      
    async with Client(transport=transport) as session:                                                                  
                                                                                                                        
        execution_result = await session.execute(                                                                       
            parse(get_introspection_query(input_value_deprecation=True))                                                
        )                                                                                                               
                                                                                                                        
        schema = build_client_schema(execution_result)                                                                  
        schema_str = print_schema(schema)                                                                               
        print(schema_str)                                                                                               
                                                                                                                        
                                                                                                                        
asyncio.run(main()) 

ok thanks

Do you plan to release a patch for that by any chance?

Do, you plan to release a patch for that by any chance?

Yes, thanks for your report!

@Cito, what arguments should we use by default in gql to make the introspection query? I'll add input_value_deprecation=True, but does it make sense to use other arguments in get_introspection_query ? What about these arguments:

  • specified_by_url
  • directive_is_repeatable
  • schema_description

Should I enable all of them?

Hi @leszekhanusz - in GraphQL.js, all of these parameters are false by default, and GraphQL-core always mimics the behavior there. I guess this is because not all servers may support these introspections (I think input value deprecation is only possible since the latest draft of the GraphQL spec). But of course you're free to use more reasonable defaults and/or make it configurable on your side, too. It may be also useful to be able to not fetch descriptions if you don't need them (which is the only parameter that is set to true by default).

You're right, I made some tests and for example the GitHub GraphQL API does not support any of those three options:

  • specified_by_url
  • directive_is_repeatable
  • schema_description

The kili-technology.com backend above support directive_is_repeatable and schema_description but we have this prob with specified_by_url:
Cannot query field "specifiedByURL" on type "__Type". Did you mean "specifiedByUrl"?

So it is clear that I cannot modify the default without a potential breaking change and users will need to specify those options themselves.

So In the PR #402 I made this configurable in the Client init and in the gql-cli script.

To download the schema with deprecated input fields, you now have to run:

gql-cli https://preproduction.cloud.kili-technology.com/api/label/v2/graphql --print-schema --schema-download input_value_deprecation:true

Hi,
I'm going to try your PR

edit: fixed the issue, thanks a lot