ariadne
ariadne copied to clipboard
Provide internal type mapping for GraphQL types from schema
Ariadne is based on idea of schema SDL being the source of truth and so it is not generated from python code, like Graphene does. There are very good reasons why we decided to build it up this way, but one of few inevitable downsides of this decision is problem with mapping input and output data typing validated by GraphQL abstraction to internal representation in business logic.
This might not seem like a big deal at first, but few problems arise quickly in service development:
- this encourages developers to neglect idea of strong typing that GraphQL centers around and pass around generic built-ins instead, leading to fuzzy abstract layer boundaries and a lot of code/logic duplication leading to code inflation and bugs
- need to write and maintain at least one extra version of communication data types inside your application in addition to those defined in interface (schema)
- getting out of sync every time schema changes, no automated way to check for regression without extra precautions, hard to track every place for alignment with interface change
Example scenario no. 1: extension of mutation input type with new field, leading to data being ignored or inconsistent runtime errors.
Example scenario no. 2: enumeration type in interface is updated, can you handle new/changed value and covered new branches in logic?
So, what solutions do we have? We would like to make use of modern language concepts, like dataclasses and type hints to enforce type safety. After discussing it internally, those appeared to be main candidates:
- utility for schema introspection from python code, ex.
Schema.get_type("SomeEnum")
or exposing all types through other means, like import hooks - static python types auto-generation based on schema using independent script, just like TypeScript types are generated on client side
- manual type mapping in ariadne, with consistency check-up on server startup, does not solve redundancy but seems to be most flexible and general solution fixing the most important downside of SDL defined service: sync between interface and implementation
This is complex issue with no obvious solution visible, so I would like us to discuss pros and cons of each one, maybe even come up with yet another one if needed. Keep in mind there is no need to find single champion since there might be no need for any enhancement or maybe there is place for multiple complementary mechanisms.
Thinking quick here, but ariadne.contrib
could include validators or linters that would compare the "Python-land" against the GraphQL schema. Eg. we could take a return type from resolver function and verify that this type is accepted by field's scalar.serialize
. Or, if resolver if for field returning object, we could verify that object's fields resolvers accept the type returned from parent. Same for arguments or inputs.
Not perfect, but another safety net in projects that need it. And it could actually do a lot.
And for projects that really need to keep everything tight, future Ariadne GraphQL Modules release will be code-first out of the box.