-
Notifications
You must be signed in to change notification settings - Fork 823
Low-resolution documentation and its solution #925
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
Comments
Personally, I find the documentation a bit terse, but not so bad that it needs to be completely rewritten. Maybe you can give a few concrete example for the kind of issues you have with the documentation or questions that you feel are not answered there. |
Hi, @Cito. I've done more reading and thinking, and I think you're probably right. The skeleton is there, but it's bare — there's just no fleshy tissue, metaphorically speaking. Take this, for instance, on the ObjectType page:
There is then an example that shows the following GraphQL schema:
I understand this GraphQL schema perfectly well. What I don't understand is what exactly is the relationship between this GraphQL schema and the Graphene representation thereof.
I attempt to write an ObjectType:
This doesn't work. Why doesn't this work? In addition, arguments can be passed to a class initialization. They are handled by This also doesn't work:
Only this works:
But in one of the examples of Mutations there's a Here's an example from the Interfaces page:
What's this SQLAlchemy. I'm trying to move away from the clusterfuck that is NPM because I really would prefer not having hundreds of megabytes of ¯\(ツ)/¯ code from literally-no-one-knows running on my servers.
...I guess the attributes are inherited somehow? More details would sure be nice. In Javascript, objects can be composed in various manner. Object destructuring, for example, is fantastic, and
Is there a way to achieve this with Python? If so, I didn't see it in the Graphene documentation, although maybe it exists. I have some more questions, like (from the official documentation):
Why is ...But I think I've covered the big ones for the most part. Finally, I suppose it's entirely possible that all of this is perfectly obvious to the Python metabolizing-and-respirating wizards of the world, but I am only "reasonably competent". |
@BenSapiens the docs on the website are unfortunately a bit out of date but I recently re-did the documentation for ObjectTypes and you can see it here: https://github.com/graphql-python/graphene/blob/master/docs/types/objecttypes.rst Also I'm unsure from your comment if you actually want answers to the questions or they are purely rhetorical? If you do want answers then I'm happy to try and answer them one by one. |
Thanks for your concrete and detailed feedback @BenSapiens. Give me 1 or 2 days to answer, since I'm currently very busy, or maybe @jkimbo will answer in the meantime. We can then decide how to improve or amend the docs to make these issues more clear for new users. |
Hi @BenSapiens. Finally found some time to answer your questions.
The GraphQL schema representation is just a description of the schema in the so called GraphQL Schema Definition Language (SDL). It's a syntax that allows describing the schema independent of the used programming language or platform. That means that this schema description leaves out the functional parts (resolvers) and platform specific details like representation of Enums as server-side values. It describes only the types used in the schema, it is just text, not live and executable. The Python object on the other hand is part of the executable schema. The ObjectType is one of the classes you need to build such a schema, which has an execute method that can be called to run queries against that schema. Note that graphql-core (the lower level library used by Graphene) provides a utility function that can automatically create a schema made of Python objects from SDL. That schema will be like the schema created manually, but lack the language and platform specific parts mentioned above. These parts (primarily the resolvers) can be added to a schema created from SDL by defining a resolver map. The Ariadne tool takes this approach. But that's different from the approach taken by Graphene, where you build your schema using Python classes. You don't need the SDL then, it is only shown in the documentation for comparison so that you know which SDL description the Graphene objects correspond to.
As I wrote above, you can also define the resolvers separately from the SDL using a resolver map. Graphene uses a different approach, since logically the resolvers belong to their respective types. It's a bit like PHP where you put the dynamic parts directly into the page at the location where they are used, and do not define them in separate files. This approach has pros and cons of course.
This is because most GraphQL implementations and Graphene as well provide you with "trivial resolvers" which you don't need to specify. The trivial resolvers will just look up the corresponding attribute or dictionary key in the object value that has been resolved one level above (or the root object value at the top level). This should really be mentioned in the docs.
Classes derived from ObjectType are used to describe object types in GraphQL. The Query object type is only special in that it is used at the root as the entry point for GraphQL queries. But other than that, it is just an object type like all the others.
In the declaration of the object type, when you give another object type as the type of one of its field, you get a nested object type. Yes, there is no limitation in depth.
Are you referring to the objects that are used to describe the schema or the object values used for the queried data?
You should always explain what exactly doesn't work (what do you expect? what happens instead)? I guess what you mean is that this schema doesn't return anything when running a query like
Then
I'm not sure what you mean here.
Yes, because resolvers always belong to one of the fields. And the resolver for the whole object must be defined on the object type one level above.
Right, now you're providing a person object value, and then make use of the trivial resolvers for the fields of that object. Btw, one thing that can be confusing is when you use the same class
This is probably one point that should be better explained in the docs.
This is because mutation fields are defined only once at the root level, they execute one clearly defined operation. Not so with query fields. Consider this:
If you define the resolver for these fields at the level of Person, you would not know whether to return friend or foe. They must have different resolvers.
Ok, I can see how this can be confusing because of "class" and "Meta". Actually this has nothing to do with Python metaclasses, it is just meta information (additional information) to tell Graphene more about the object type. In this case, the information which interfaces the object type implements. This syntax is used to distinguish this attribute from the normal fields attributes.
The
Yes, they are taken from the model class by default. You can also exclude and include certain fields. This is documented separately in graphene-sqlalchemy. But yes, that project and its documentation needs more love as well. graphene-django currently gets much more attention, tough I personally also favor SQLAlchemy over the Django ORM.
It looks like you're referring to resolver maps here. As explained, that's a different approach from Graphene where you structure your resolvers with your types. I think you can do something similar in Ariadne, where you pass a resolver list, which could be a concatenation of lists imported from different modules. And of course, Python has something similar to the destructuring and spread operators in JavaScript: the
In the first case, it's a special field that is provided by that particular mutation. In the second case, it's a general field of the given type. I hope this answers your questions and will help in identifying where we can improve the documentation. |
@jkimbo, Thanks for the reply. To answer your question, no, these questions are not at all rhetorical; they accurately represent my current state of intellectual development vis-à-vis Graphene (and to some extent GraphQL, having for the most part used only I really appreciate your response, @Cito. I'm going to let it rattle around in my brain for a while, and explore |
@jkimbo and @Cito, I've also added a rudimentary beginning for an FAQ on the wiki here addressing an issue I struggled with as an example. First, is that ok, and second, is it welcome? (Fourth, on the semantic side, I always struggle with FAQ grammatically. Whether it should be 'a fack' or 'an eff-a-q.' Feel free to toss your hat in on this. ::grin::) |
I think using the Wiki is a good idea. Will address this at the next meeting. I hope we can also find someone who will serve particularly as a documentation maintainer for Graphene. |
I submitted a couple of PR for updating documentation. Adds an autodoc API reference for core Graphene and some nicer hooks for Documentation developer experience: #971 Attempt at explaining resolvers better and giving first time users of the library a smoother transition: #969 There are a couple of other open docs-related PR as well: I'll be on the call next week, so hopefully we can figure out how to move forward with refining the documentation further! |
I believe there would be value in harvesting StackOverflow, issues found here and in the other components of the ecosystem, in tutorials and blogs, and elsewhere where relevant, for clear pain-points and creating a triage list of such pain points caught in the wild to address in the docs. I'm considering where these might best be collected, either within a living issue entry, a wiki page, a TODO-style document in the source, a repo Thoughts on this, is there value, where (and how) best to collect these for review? IS this something that would be welcome or useful? |
Added a CORS/CSRF quickie to the |
A few PRs improving docs have been merged (thanks @dvndrsn and @changeling !) so I'm going to close this issue for now in favour of tracking this under the main #823 issue. |
Sorry for the radio silence, I intend to come back to this in a bit. |
I'm trying to figure out this software and I'm having a hell of a time. The documentation just doesn't explain much of anything. If someone with domain expertise would like to walk me through this thing, I'll write you up a whole new set of docs with what I've learned, start to finish. That's a fair trade, I think.
The text was updated successfully, but these errors were encountered: