Public GraphQL directives - graphql

This is my Schema.
Query {
me: User #isAuthenticated
}
When I add #isAuthenticated it is handled on server side but in GraphQL Playground the directive doesn't show. I have some role based access system and I want to show all the role directives publicly so that API user can understand what role is wanted for which query.

Schema directives can be used to transform the schema or add functionality to it, but they cannot be used to expose any sort of metadata to the client. There's ongoing discussion here with regards to how to implement that sort of functionality. For the time being, your best bet would be to utilize descriptions.
"""
**Required roles**: `ADMIN`
"""
Query {
me: User #isAuthenticated
}

Related

Can Queries be used for data writing?

For my GraphQL app I'd like to save logs of certain resolved fields. Because the users can view these logs themselves, should that be considered apart of a mutation instead of a query?
Since it's not the application's focus I'd assume that using a mutation is overkill, but I'm not sure if there's some sort of side effects I'm going to run into by modeling it in such a way.
The other questions I've read didn't really answer this question, so sorry if this seems like a duplicate.
Conceptually Graphql Queries & Mutations do the same thing but however differ in the way the resolvers are executed.
For the following Queries:
{
user {
name
}
posts {
title
}
}
The GraphQL implementation has the freedom to execute the field entries in whatever order it deems optimal. see here.
For the following Mutations:
{
createUser(name: $String) {
id
}
addPost(title: $String) {
id
}
}
The GraphQL implementation would execute each Mutation sequentially. see here
Par from this, the Mutation keyword is just a bit of syntax to say "hey this is gonna edit or create something". I think here, in your case, its a better decision to perform a Query & store the event in your Audit log. Exposing the fact that the Query stores an audit log is an implementation-specific detail & clients shouldn't know about it.

Apollo Client: can apollo-link-rest resolve relations between endpoints?

The rest api that I have to use provides data over multiple endpoints. The objects in the results might have relations that are are not resolved directly by the api, it rather provides ids that point to the actual resource.
Example:
For simplicity's sake let's say a Person can own multiple Books.
Now the api/person/{i} endpoint returns this:
{ id: 1, name: "Phil", books: [1, 5, 17, 31] }
The api/book/{i} endpoint returns this (note that author might be a relation again):
{ id: 5, title: "SPRINT", author: 123 }
Is there any way I can teach the apollo client to resolve those endpoints in a way that I can write the following (or a similar) query:
query fetchBooksOfUser($id: ID) {
person (id: $id) {
name,
books {
title
}
}
}
I didn't try it (yet) in one query but sould be possible.
Read docs strating from this
At the beggining I would try with sth like:
query fetchBooksOfUser($id: ID) {
person (id: $id) #rest(type: "Person", path: "api/person/{args.id}") {
name,
books #rest(type: "Book", path: "api/book/{data.person.books.id}") {
id,
title
}
}
}
... but it probably won't work - probably it's not smart enough to work with arrays.
UPDATE: See note for similiar example but using one, common parent-resolved param. In your case we have partially resolved books as arrays of objects with id. I don't know how to use these ids to resolve missing fields () on the same 'tree' level.
Other possibility - make related subrequests/subqueries (someway) in Person type patcher. Should be possible.
Is this really needed to be one query? You can provide ids to child containers, each of them runing own query when needed.
UPDATE: Apollo will take care on batching (Not for REST, not for all graphql servers - read docs).
'it's handy' to construct one query but apollo will cache it normalizing response by types - data will be stored separately. Using one query keeps you within overfetching camp or template thinking (collect all possible data before one step rendering).
Ract thinking keeps your data and view decomposed, used when needed, more specialised etc.
<Person/> container will query for data needed to render itself and list of child-needed ids. Each <Book/> will query for own data using passed id.
As an alternative, you could set up your own GraphQL back-end as an intermediary between your front-end and the REST API you're planning to use.
It's fairly easy to implement REST APIs as data sources in GraphQL using Apollo Server and a package such as apollo-datasource-rest which is maintained by the authors behind Apollo Server.
It would also allow you to scale if you ever have to use other data sources (DBs, 3rd party APIs, etc.) and would give you full control about exactly what data your queries return.

single permissions in search guard

I went through the latest documentation of search guard, https://docs.search-guard.com/latest/roles-permissions and could only find a short explaination for single permissions:
Single permissions either start with cluster: or indices:, followed by
a REST-style path that further defines the exact action the permission
grants access to.
So one permission could be on cluster level or on indices level.
indices:data/read/search
So the part before : could be indices or cluster, but I'm not clear how to understand the parts after semicolon, and what are these parts seperated by "/".
Can someone please explaine me more about this or point me to some documentation, which I maybe missed?
Thanks
Dingjun
This is actually not related to Search Guard but to Elasticsearch. When you interact with Elasticsearch, e.g. indexing data or searching data, what you are really doing is executing actions. Each action has a name, and this name is in the format you outlined.
For example, have a look at org.elasticsearch.action.search.SearchAction:
public class SearchAction extends Action<SearchRequest, SearchResponse, SearchRequestBuilder> {
public static final SearchAction INSTANCE = new SearchAction();
public static final String NAME = "indices:data/read/search";
private SearchAction() {
super(NAME);
}
...
}
The permission schema of Search Guard is based on these Elasticsearch action names. So the naming conventions is actually an Elasticsearch naming convention.
Elastic does not publish a list of these action names anymore. AFAIK in X-Pack Security you cannot actually go down to this level of detail regarding permissions, that's probably why they stopped to do so.
The Search Guard Kibana plugin comes with a list of permissions you might use as a guideline:
https://github.com/floragunncom/search-guard-kibana-plugin/blob/6.x/public/apps/configuration/permissions/indexpermissions.js
https://github.com/floragunncom/search-guard-kibana-plugin/blob/6.x/public/apps/configuration/permissions/clusterpermissions.js
The question is if you really need to implement security on such a fine-grained level. That's what the action groups are for. These are pre-defined sets of permissions and should cover most use cases. Also, they are updated with each release if the permissions in Elasticsearch change, so it's safer to use action groups than to rely on single permissions. But as always, it depends on the use case.

graphql multiple mutations using prior mutation return results?

I understand that mutations are sequential, so it makes sense to me that if Mutation 1 creates an entity and returns an id, that Mutation 2 should have access to that id. However I don't see any examples online and can't seem to get it to work. I see that people say you need to handle this in the resolve function of your route but it seems like extra unnecessary code if I can get this in just the query.
For example I have the following where accounts belong to clients and hence need the clientId before being created. However this does not work...
mutation createClientAndAccount($account: AccountInput, $client: ClientInput){
createClient(client: $client){ clientId }
createAccount(account: $account, clientId: USE_CLIENT_ID_FROM_ABOVE) { ... }
}
I've also tried nesting mutations but didn't have much luck there either...
Is what i'm trying to do possible? Would the resolve function of createAccount have the return data from createClient?
This is not possible right now, though would be useful.
See this PR.
Maybe using a custom schema directive we could achieve that.
Schema stitching will be a better approach(though usually it is preferred in API Gateway for merging APIs from different services).
If this requirement is very rare in your application, simply creating a new API that can do both CreateClientAndAccount is enough.

What is the point of naming queries and mutations in GraphQL?

Pardon the naive question, but I've looked all over for the answer and all I've found is either vague or makes no sense to me. Take this example from the GraphQL spec:
query getZuckProfile($devicePicSize: Int) {
user(id: 4) {
id
name
profilePic(size: $devicePicSize)
}
}
What is the point of naming this query getZuckProfile? I've seen something about GraphQL documents containing multiple operations. Does naming queries affect the returned data somehow? I'd test this out myself, but I don't have a server and dataset I can easily play with to experiment. But it would be good if something in some document somewhere could clarify this--thus far all of the examples are super simple single queries, or are queries that are named but that don't explain why they are (other than "here's a cool thing you can do.") What benefits do I get from naming queries that I don't have when I send a single, anonymous query per request?
Also, regarding mutations, I see in the spec:
mutation setName {
setName(name: "Zuck") {
newName
}
}
In this case, you're specifying setName twice. Why? I get that one of these is the field name of the mutation and is needed to match it to the back-end schema, but why not:
mutation {
setName(name: "Zuck") {
...
What benefit do I get specifying the same name twice? I get that the first is likely arbitrary, but why isn't it noise? I have to be missing something obvious, but nothing I've found thus far has cleared it up for me.
The query name doesn't have any meaning on the server whatsoever. It's only used for clients to identify the responses (since you can send multiple queries/mutations in a single request).
In fact, you can send just an anonymous query object if that's the only thing in the GraphQL request (and doesn't have any parameters):
{
user(id: 4) {
id
name
profilePic(size: 200)
}
}
This only works for a query, not mutation.
EDIT:
As #orta notes below, the name could also be used by the server to identify a persistent query. However, this is not part of the GraphQL spec, it's just a custom implementation on top.
We use named queries so that they can be monitored consistently, and so that we can do persistent storage of a query. The duplication is there for query variables to fill the gaps.
As an example:
query getArtwork($id: String!) {
artwork(id: $id) {
title
}
}
You can run it against the Artsy GraphQL API here
The advantage is that the same query each time, not a different string because the query variables are the bit that differs. This means you can build tools on top of those queries because you can treat them as immutable.

Resources