Why does GraphQL query work with the "query" keyword before the curly braces? - asp.net-core

I created a small API for authors and books as example. The problem is that I don't understand why a query can look different but still get me the same output. I've included 3 examples.
The GraphQL query looks like this:
{
"query":
"query{
author(id: 1) {
name
}
}"
}
Why is this query working if within the query is the keyword "query" two times? When I write the query like this:
{
"query":
"{
author(id: 1) {
name
}
}"
}
it also works, and when I write it like that:
{
"query":
"author{
author(id: 1) {
name
}
}"
}
It is not working. Why is that so?

GraphQL specifies three types of operations:
query – a read‐only fetch.
mutation – a write followed by a fetch.
subscription – a long‐lived request that fetches data in response to source events.
What you are sending to your server is a JSON object with a single property (query) the value of which is a GraphQL document that represents your actual request to the GraphQL service. This property is (unfortunately) called query by convention but it has nothing to do with the actual operation inside the document you are sending.
Any operation included in your GraphQL document must follow this format:
OperationType [Name] [VariableDefinitions] [Directives] SelectionSet
Name, VariableDefinitions and Directives are all optional. The OperationType is one of query, mutation or subscription. SelectionSet is the collection of fields you are requesting for that operation type. Only selection sets are wrapped in curly brackets. In your example, you have two selection sets -- one containing the author field and one containing the name field.
There's an exception to the above called query shorthand:
If a document contains only one query operation, and that query defines no variables and contains no directives, that operation may be represented in a short‐hand form which omits the query keyword and query name.
In other words if your operation:
is a query
is the only operation in the document
contains no variable definitions or directives
You can omit the query keyword and the operation name. This leaves you with just a selection set, which is wrapped in a set of curly brackets.
So your first two examples are equally valid. The third example is not valid because author is not a valid operation kind.

The first query key on your examples is a requirement from GraphQL to actually call the endpoint, it has to be present to actually run queries or mutations. You can see it in the docs.
The first example works because at the root of a GraphQL Schema there has to be an action with keywords query or mutation, and in your case you are triggering a query.
The second example works because if you don't define what type of action (query or mutation) on your request, it always defaults to execute a query.
The third example does not work because you don't have the action author at the root of your Schema.
I guess the first keyword query is what makes some confusion in this case.

Related

Representing complex data types in XACML using Authzforce

I am new to XACML and I would be grateful if you can help me with one problem I encountered.
I use AuthzForce Core PDP (version 17.1.2).
I am wondering what is the correct approach of representing complex data types in XACML.
Example
Access should be granted if PIP response contains any person whose name is present in names array from request and salary of that person is higher than salary provided in request.
Request
names = ["Eric", "Kyle"]
salary = 1500
PIP response
[
{
"name": "Kyle",
"salary": 1000
},
{
"name": "Kenny",
"salary": 2000
},
{
"name": "Eric",
"salary": 4000
},
{
"name": "Stan",
"salary": 3000
}
]
Access will be granted because PIP response contains person with name Eric and his salary is higher than 1500.
My implementation
To represent PIP response I ended up with creating custom type by extending StringParseableValue class from AuthzForce. For above mentioned logic I use attribute designator in xml and have coresponding attribute provider (class extending BaseNamedAttributeProvider) in Java performing PIP call.
I also wrote two custom functions:
Find people with higher salary than provided in one param (returns filtered list)
Get person name (returns string)
And using those functions and standard function I wrote policy and it works.
However my solution seems to be overcomplicated. I suppose what I did can be achieved by using only standard functions.
Additionally if I wanted to define hardcoded bag of people inside other policy single element would look like this:
<AttributeValue DataType="person">name=Eric###salary=4000</AttributeValue>
There is always possibility that parsing of such strings might fail.
So my question is: What is a good practice of representing complex types like my PIP response in XACML using Authzforce? Sometimes I might need to pass more complex data in the request and I saw example in XACML specification showing passing such data inside <Content> element.
Creating a new XACML data-type - and consequently new XACML function(s) to handle that new data-type - seems a bit overkill indeed. Instead, you may improve your PIP (Attribute Provider) a little bit, so that it returns only the results for the employees named in the Request, and only their salaries (extracting them from the JSON using JSON path) returned as a bag of integers.
Then, assuming this PIP result is set to the attribute employee_salaries in your policy (bag of integers) for instance, and min_salary is the salary in the Request, it is just a matter of applying any-of(integer-less-than, min_salary, employee_salaries) in a Condition. (I'm using short names for the functions by convenience, please refer to the XACML 3.0 standard for the full identifiers.)
Tips to improve the PIP:
One issue here is performance (scalability, response time / size...) because if you have hundreds even thousands of employees, it is overkill to get the whole list from the REST service over and over, all the more as you need only a small subset (the names in the Request). Instead, you may have some way to request the REST service to return only a specific employees, using query parameters; an example using RSQL (but this depends on the REST service API):
HTTP GET http://rest-service.example.com/employees?search=names=in=($employee_names)
... where you set the $employee_names variable to (a comma-separated list of) the employee names from the Request (e.g. Eric,Kyle). You can get these in your AttributeProvider implementation, from the EvaluationContext argument of the overriden get(...) method (EvaluationContext#getNamedAttributeValue(...)).
Then you can use a JSON path library (as you did) to extract the salaries from the JSON response (so you have only the salaries of the employees named in the Request), using this JSON path for instance (tested with Jayway):
$[*].salary
If the previous option is not possible, i.e. you have no way of filtering employees on the REST API, you can always do this filtering in your AttributeProvider implementation with the JSON path library, using this JSON path for instance (tested with Jayway against your PIP response):
$[?(#.name in [$employee_names])].salary
... where you set the $employee_names variable like in the previous way, getting the names from the EvaluationContext. So the actual JSONpath after variable replacement would be something like:
$[?(#.name in [Eric,Kyle])].salary
(You may add quotes to each name to be safe.)
All things considered, if you still prefer to go for new XACML data-type (and functions), and since you seem to have done most of the work (impressive btw), I have a suggestion - if doable without to much extra work - to generalize the Person data-type to more generic JSON object datatype that could be reused in any use case dealing with JSON. Then see whether the extra functions could be done with a generic JSONPath evaluation function applied to the new JSON object data-type. This would provide a JSON equivalent to the standard XML/XPath data-type and functions we already have in XACML, and this kind of contribution would benefit the AuthzForce community greatly.
For the JSON object data-type, actually you can use the one in the testutils module as an example: CustomJsonObjectBasedAttributeValue which has been used to test support of JSON objects for the GeoXACML extension.

Wikibook API query

I am trying to understand how to build an API call where I can get data (json format) for the recipes, ingredients, and procedure as mention here. Anyone who could help me out with this?
https://en.wikibooks.org/wiki/Cookbook:Recipes
This URL has the recipe names and when clicked on each item it gets the ingredients and the procedure.
To get all recipes I would not use Cookbook:Recipes but rather Category:Recipes which is more complete.
The API call to list all recipes which are listed in Category:Recipes is the following:
https://en.wikibooks.org/w/api.php?action=query&generator=categorymembers&gcmtitle=Category:Recipes&gcmlimit=max&format=json&gcmcontinue=.
It will return you 500 recipes but there are more on Wikibooks. To get the remaining ones, use the continue -> gcmcontinue value in the response and append it to the next API call.
To get the ingredients and procedure of a recipe, call for example
https://en.wikibooks.org/w/api.php?action=query&prop=revisions&format=json&rvprop=content&rvslots=%2A&rvsection=1&titles=Cookbook:Biscuits.
You can use the | character to retrieve multiple recipes with the same API call:
https://en.wikibooks.org/w/api.php?action=query&prop=revisions&format=json&rvprop=content&rvslots=%2A&titles=Cookbook:Biscuits|Cookbook:Baklava.
If you want to retrieve only the ingredients or only the procedure of recipes, use the additional parameter rvsection=. Most of the time (but not always) the ingredients are in the first section and the procedure is the second section. So calling
https://en.wikibooks.org/w/api.php?action=query&prop=revisions&format=json&rvprop=content&rvslots=%2A&rvsection=1&titles=Cookbook:Biscuits&rvsection=1 returns you the ingredients for making biscuits and
https://en.wikibooks.org/w/api.php?action=query&prop=revisions&format=json&rvprop=content&rvslots=%2A&rvsection=1&titles=Cookbook:Biscuits&rvsection=2 returns you the procedure for making biscuits.
I'm not sure if it was your question, but in addition to Pascalco's answer, it worth note that you will NOT be able to get structured json data that details ingredients with their quantities and procedures, ie something like:
{ "ingredient": "milk", "quantity": { "number": "1", "unit":"liter"}}
The API will drop the raw mediawiki's syntax page content in one single field, and a few extra metadata about the page.
Moreover, the fact that those pages do not use templates make this type of data very difficult to extract, either with a syntax parser or html parser.

Add row to Eloquent Collection by default based on raw query

In my Eloquent collections, I'd like to add an extra column called "editable". "Editable" should be included in each query I run on some models. "Editable" show either be true or false, based on a raw query.
So I have a query that should be runned in each query on my models. Adding an extra column to my collection. The value of "editable" is determined by a raw query.
What is the best way to do this?
You could add an addSelect() method to your query chain to include the custom attribute..
Something like
$results = YourModelClass::select("*")
->addSelect(DB::raw("IF(condition,1,0) AS editable"))
->get();
In the above case, you would replace condition with your relevant SQL statement that would be evaluated per-row as part of the query. If the statement is true, then editable = 1 and if false then editable = 0 for each row returned to your Collection.
EDIT: I just saw that you want this on every query, so you probably would need a global scope/trait for your models, but the above technique for including the extra attribute should be the correct one.
I won't copy/paste the documentation on adding global scopes, that's in the core Laravel docs and I'm sure you can find it.
You can add a custom getter to your model:
public function getEditableAttribute()
{
/* return result from your raw query here */;
}

Native Query Mapping on the fly openJPA

I am wondering if it is possible to map a named native query on the fly instead of getting back a list of Object[] and then looping through and setting up the object that way. I have a call which I know ill return a massive data set and I want to be able to map it right to my entity. Can I do that or will I have to continue looping through the result set.
Here is what I am doing now...
List<Provider> ObjList = (List<Provider>) emf.createNativeQuery(assembleQuery(organizationIDs, 5)).getResultList();
That is my entity, the List (my entity is the provider). Normally I would just return a List<Object[]>
and then I would loop through that to get back all the objects and set them up as new providers and add them to a list....
//List<Provider> provList = new ArrayList<Provider>();
/*for(Object[] obj: ObjList)
{
provList.add(this.GetProviderFromObj(obj));
}*/
As you can see I commented that section of the code out to try this out. I know you can map named native queries if you put your native query in the entity itself and then call it via createNamedQuery. I would do it that way, but I need to use the IN oracle keyword because I have a list of ID's that I want to check against. It is not just one that is needed. And as we all know, native queruies don't handle the in keyword to well. Any advice?
Sigh, If only the IN keyword was supported well for NamedNativeQueries.
Assuming that Provider is configured as a JPA entity, you should be able to specify the class as the second parameter to your createNativeQuery call. For example:
List<Provider> ObjList = (List<Provider>) emf.createNativeQuery(assembleQuery(organizationIDs, 5), Provider.class).getResultList();
According to the documentation, "At a minimum, your SQL must select the class' primary key columns, discriminator column (if mapped), and version column (also if mapped)."
See the OpenJPA documentation for more details.

Filter RavenDB Search Results

I have a query that returns valid search results using the IRavenQueryable.Search method. However, I want to further filter those results via a .Where method call such that the search results are then filtered to only include those that have the matching ProjectId.
My object structure is a set of Project entities each containing a collection of Issue entities.
My index creates a projection of Issue Search Results that looks like:
{Id, Key, Summary, Description, ProjectId, ProjectKey, Query}
The Query property is an object[] that is used by the keyword search.
When I run the keyword search:
var results = session.Query().AsProjection().Search(x => x.Query, "some key word");
I get the right results back. But when I try to also apply the Where method:
results = results.Where(i => i.ProjectId == SelectedProject.Id);
It does not filter the results, but instead includes all other results with matching Project Id's.
What is the correct way to force Linq or RavenDB's IRavenQueryable to apply an AND instead of an OR in this scenario?
After posting this question I managed to find the answer elsewhere on stackoverflow.
Here is the solution:
ravendb combining Search with Where
In a nutshell, the Search method provides an extra optional parameter [options] to allow you to specify how the search is combined with other where clauses in the query. It defaults to SearchOptions.Or so you need to explicitly set it to options: SearchOptions.And.