Open jazithedev opened 4 years ago
This is not possible right now out-of-the-box but you could create a command with a "mocked" user with valid authorization or you could try to override isGranted
expression function.
@ktrzos you are intentionally using public instead of access?
I came across same issue and after a thought realized I was thinking the wrong way - its not actually an issue, but a misused feature in many cases.
Using public is like creating different graphql schemas. Because even if you dump schema with some mocked role, you get only the schema of the view for that role. If you mock somehow, to always return true on public, when run via CLI, you get a schema, that is probably not seen by all user roles. If you use this full schema on the client, the next consequence will be to implement knowledge on the client, when you are allowed to query a field and when not, because the client has the field, but the backend determines that the field does not exist (based on public expression).
Especially when you have many (conditionally) public fields, it might create multiple possible schemas based on how many different conditions you have. If you deliver full schema to client, the question is: why do you hide if from the schema on the backend at all? Then access is probably the better approach. It can be even better "documented" to the client, because when you use access, you must consider the field being possibly null and you have to declare it nullable. So the client can check if it gets anything and render the resource not available if null is returned, without repeating the knowledge/logic of the backend on the client side.
Just as a consideration ;)
@akomm
you are intentionally using public instead of access?
To be honest, in that moment I was just playing around with "overblog/GraphQLBundle". Was trying to use and test separate features, including public/access. Had no particular business logic use case for this.
But back to your comment. It's interesting approach of thinking, and I will surely consider it :). But what comes to my mind now is one question. What is the purpose of "public" then? When is the best moment to use it? Is it just good for places, where you have one GraphQL endpoint available to two (or more) separate systems (and those systems would have different GraphQL fields visibility)? Or maybe something else?
@ktrzos
To answer the question: I would not use public
at all. Let me elaborate:
First: I did not implement the public
feature, so I can not tell what its intended use-case was/is. It conditionally removes fields from the graphql schema. When a field is conditionally removed, its as if it was never defined in the schema.
When you dump the schema, you are querying for the types (introspection), which includes object types and its fields. And those fields depend on public
. So public
has to be evaluated. Access
on the other hand is used when you are querying for data. So when you dump schema, it does not have to be evaluated - you are not querying for data, but types!
Now you realize, it makes sense for the dump command to ask you for all the dependencies/data, which is required to decide which schema will get dumped.
Having this definition:
Query:
type: 'object'
config:
fields:
foo:
type: 'String!'
public: '@=hasRole("ROLE_ADMIN")'
bar:
type: 'String!'
foobar:
type: 'String!'
public: '@=hasAnyRole("ROLE_ADMIN", "ROLE_EDITOR")'
You would effectively produce 3 different schemas, based on which role the user has:
# 1. ROLE_ADMIN schema
type Query {
foo: String!
bar: String!
foobar: String!
}
# 2. ROLE_EDITOR schema
type Query {
bar: String!
foobar: String!
}
# 3. other role schema
type Query {
bar: String!
}
If you you have other conditions and more fields, it gets messier, because possibilities can multiply to different combinations. Conditions may be also less obvious than simple role-checks. So you can end up hardly being able to tell which user will see what schema. Example: When you condition to time and/or some state in the app, you can't tell which user at which time and which app state will have what schema. So if you use it at all, you should not use it to describe absence of something at certain time or state. Its rather to hide parts of API from certain consumers.
Assuming you use it, you now have 3 different schemas. What do you do with it?
Do you want to implement a frontend, that somehow swaps those 3 schemas depending on what user authorized? This essentially means, your frontend has to know which schema corresponds to which role.
Do you want to implement some mock, so that the command dumps schema as if public is always true? When you deploy it to the frontend, the frontend would see the FULL schema, but would have to know what fields it is not allowed to query based on which conditions on the backend. The question arises also: why do you deploy the full schema to frontend, but then evaluate queries against a dynamic schema on the backend? The purpose of hiding it from consumer has been missed here.
Its important, that when a consumer has a schema, he can assume all the fields and types being available, as in the schema, or else it will be a hard to consume API and error prone.
If you have multiple clients for your API and let's say they have subscription for different service levels with different API features and you want to hide the inaccessible API, then I would simply create different schemas. Its supported by the bundle. Different schemas more declarative by defining that its a different schema so you do not have to compute what schemas you have based on conditions. You can still share types between different schemas. And you can dump the schema you want, because there is an dump command option for that. The is however currently a drawback to this approach in regards to naming: https://github.com/overblog/GraphQLBundle/issues/644
Use it only when you really want consumers to have different schemas available, otherwise either use access
or let let it be part of the resolve logic or the authorization layer behind it. Access is maybe convenient from schema definition perspective, but its actually an integration of authorization at the wrong place. Use it in simple projects, there is no problem. But not if you design something really sophisticated.
Hi. I've got this simple type configuration:
When trying to generate schema
I'm getting an error:
How can I "mock" this in the way, that the
public: ... isGranted('ROLE_ADMIN')
will return TRUE? Or is there any other way, or only by using custom service?