在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):deeprjs/deepr开源软件地址(OpenSource Url):https://github.com/deeprjs/deepr开源编程语言(OpenSource Language):TypeScript 95.6%开源软件介绍(OpenSource Introduction): |
Deepr | GraphQL | REST | |
---|---|---|---|
Root queries | |||
Deep queries | |||
Sequential queries | |||
Parallel queries | |||
Aliases | |||
Unnesting | |||
Root mutations | |||
Deep mutations | |||
Collections | |||
Collection items | |||
Collection slices | |||
Source values | |||
No additional layer | |||
Type system | (1) | ||
Introspection | (3) | ||
No extra language | |||
Subscriptions | (1) |
Deepr does not specify the use of a particular language. So, although the following examples are written in JSON, keep in mind that any language could be used.
Note: To fully appreciate this guide, it is recommended to have a minimum knowledge of GraphQL.
Let's start with a simple query:
{
"movie": {
"title": true,
"year": true
}
}
Here we are querying an object called movie
in the top-level context (the "root").
Then, inside the context of movie
, we are getting title
and year
fields.
The response will be:
{
"movie": {
"title": "Inception",
"year": 2010
}
}
So far, it looks like GraphQL. Since we are using JSON objects, the only significant difference is that we must specify a value for the keys title
and year
. Specifying true
means that we want to return the corresponding field.
Instead of querying a single movie, let's query a collection of movies:
{
"movies": {
"count": true
}
}
Nothing surprising here, we are just querying the count
field on the movies
collection. The query will return:
{
"movies": {
"count": 2
}
}
Now, you might ask yourself, how can I reach the items of the movies
collection? That is easy:
{
"movies": {
"[]": [],
"title": true,
"year": true
}
}
By using the special key []
, we specify that the context of the query is the items of the collection rather than the collection itself. We get the following response:
{
"movies": [
{
"title": "Inception",
"year": 2010
},
{
"title": "The Matrix",
"year": 1999
}
]
}
The value associated with the special key []
can be an empty array, an array of one or two numbers, or a simple number.
With an empty array (such as in the previous example), we get all the items of a collection.
With an array of numbers, we get a slice of a collection in a similar way to the slice()
method in JavaScript. For example, to get the first two items of the movies
collection, we can use the following query:
{
"movies": {
"[]": [0, 2],
"title": true,
"year": true
}
}
We get the following response:
{
"movies": [
{
"title": "Inception",
"year": 2010
},
{
"title": "The Matrix",
"year": 1999
}
]
}
To get the last two items of a collection, we can use a negative index:
{
"movies": {
"[]": [-2],
"title": true,
"year": true
}
}
Finally, to get a particular item in a collection, we can use a simple number. For example, to get the first item of the movies
collection, we can write:
{
"movies": {
"[]": 0,
"title": true,
"year": true
}
}
Note that in this case the item is returned directly, and it is not embedded in an array like in the previous examples:
{
"movies": {
"title": "Inception",
"year": 2010
}
}
Now, let's see how to query both a collection and its items:
{
"movies": {
"count": true,
"=>items": {
"[]": [],
"title": true,
"year": true
}
}
}
Using the key "=>items"
means that we take the current context (the collection of movies) and we put it under a new key called items
(more explanation on this topic later). As a result, we get the following:
{
"movies": {
"count": 2,
"items": [
{
"title": "Inception",
"year": 2010
},
{
"title": "The Matrix",
"year": 1999
}
]
}
}
So far, we have seen how to query fields. Let's now see how to invoke methods:
{
"getMovie": {
"()": [{"id": "abc123"}],
"title": true
}
}
The special key ()
indicates that we want to invoke the getMovie
method with the parameters specified in the corresponding array.
We get the following result:
{
"getMovie": {
"title": "Inception"
}
}
We have seen previously some examples involving the arrow symbol =>
; let's now go into the details of this powerful feature.
Object keys are made of two parts, a "source" and a "target", separated by the arrow symbol =>
.
Source, target, or both can be omitted, producing slightly different results. Let's check the five possible variants.
"key"
variant (mirror)If there is no arrow symbol it means that source and target are the same. This is the most frequent use-case, when the response structure mirrors exactly the query structure.
{
"movie": {
"title": true
}
}
Note: The key
title
could be expressed bytitle=>title
; it would work too.
Not surprisingly, this will return something like this:
{
"movie": {
"title": "Inception"
}
}
"sourceKey=>targetKey"
variant (alias)If source and target are different, the result of the evaluation of sourceKey
will appear under a key called targetKey
in the response.
For example createdAt=>date
key means the createdAt
field value will appear under a key called date
in the response.
You can think about it as a way to create aliases, similarly to the GraphQL's aliasing feature.
By using aliases, it is possible to execute a method more than once with different parameters, avoiding name collisions inside the result.
For example, in the following query, we first call the getMovies
method and assign the result to actionMovies
, then we call the same getMovies
method, with different parameters, and assign the result to dramaMovies
.
{
"getMovies=>actionMovies": {
"()": [{"filter": {"genre": "action"}}],
"=>": {
"[]": [],
"title": true
}
},
"getMovies=>dramaMovies": {
"()": [{"filter": {"genre": "drama"}}],
"=>": {
"[]": [],
"title": true
}
}
}
Doing this we get both actionMovies
and dramaMovies
results in the response, like this:
{
"actionMovies": [
{
"title": "Inception"
},
{
"title": "The Matrix"
}
],
"dramaMovies": [
{
"title": "Forrest Gump"
}
]
}
"=>targetKey"
variant (nest)If the source is omitted, it means the current context will be re-used in the response as it is, without any processing.
For example, in the following query, =>items
means we take the current context and put it inside an object whose key is items
. Basically, we are nesting the current context one level deeper, under a new key.
{
"movies": {
"count": true,
"=>items": {
"[]": [],
"title": true
}
}
}
Doing this, we can query both a collection and its items to produce results such as:
{
"movies": {
"count": 2,
"items": [
{
"title": "Inception"
},
{
"title": "The Matrix"
}
]
}
}
"sourceKey=>"
variant (unnest)If the target is omitted, it means that the evaluation of a method (or field) does not generate a new object. We call this feature "Unnesting".
For example, if we are only interested in the title of the movie we found, we can do this:
{
"movie": {
"title=>": true
}
}
Because we use the key "title=>"
instead of "title"
, the key title
is absent from the response:
{
"movie": "Inception"
}
"=>"
variant (return)Lastly, we can remove both the source and the target from the key expression, leaving alone the arrow symbol =>
.
In this case, we do not process the current context (no source) and we are not creating new keys in the response (no target).
The =>
can be interpreted as a way to introduce the result of a function call.
In the following query, we retrieve a movie by its id
, and we return title
and year
fields in the response.
{
"getMovie": {
"()": ["cjrts72gy00ik01rv6eins4se"],
"=>": {"title": true, "year": true}
}
}
Note that the following query is exactly the same:
{
"getMovie": {
"()": ["cjrts72gy00ik01rv6eins4se"],
"title": true,
"year": true
}
}
Both queries will produce the following response:
{
"getMovie": {
"title": "Inception",
"year": 2010
}
}
This feature is particularly useful to access the items of a collection. For example:
{
"getMovies": {
"()": [{"filter": {"country": "USA"}}],
"=>": {
"[]": [],
"title": true
}
}
}
Will output:
{
"getMovies": [
{"title": "Inception"},
{"title": "The Matrix"},
{"title": "Forest Gump"}
]
}
Query objects are evaluated in a recursive way, and for every key the related value can be either:
true
Let's see how Deepr handles these three types of values.
true
The boolean true
means the value of a field will be included as is in the response.
If we query a single movie this way:
{
"movie": {
"title": true,
"year": true
}
}
We get the following result:
{
"movie": {
"title": "Inception",
"year": 2010
}
}
When the value is an object, the execution continues recursively:
{
"movie": {
"director": {
"name": true
}
}
}
As expected, this will produce:
{
"movie": {
"director": {
"name": "George Lucas"
}
}
}
Finally, by using an array, we can specify a sequence of subqueries to be executed in order. For example:
{
"movies": [
{
"getByTitle=>": {
"()": ["Inception"],
"title": true
}
},
{
"getByTitle=>": {
"()": ["The Matrix"],
"title": true
}
}
]
}
Will return:
{
"movies": [{"title": "Inception"}, {"title": "The Matrix"}]
}
If you add a question mark (?
) after the name of a key, then no error will be thrown in case a field or a method is missing during the execution of a query.
For example, the following query will succeed even if the movie has no director:
{
"movie": {
"title": true,
"director?": {
"fullName": true
}
}
}
Rather than throwing an error, this will just return:
{
"movie": {
"title": "Inception"
}
}
Now, let's put into practice what we have just seen to compose a more complex query:
{
"movies": {
"filter=>": {
"()": [{"country": "USA"}],
"sort=>": {
"()": [{"by": "year"}],
"skip=>": {
"()": [5],
"limit=>": {
"()": [10],
"=>": {
"[]": [],
"title": true,
"year": true
}
}
}
}
}
}
}
Despite the fact that we have nested several method calls, this will just return:
{
"movies": [
{
"title": "The Matrix",
"year": 1999
},
{
"title": "Inception",
"year": 2010
}
]
}
So far we have invoked methods that read data without producing any side effects on the server. Let's fix that by executing some simple CRUD operations.
Here is how we could create a record:
{
"movies=>": {
"create=>movie": {
"()": [{"title": "Avatar", "country": "USA"}],
"=>": {"id": true}
}
}
}
Unlike GraphQL, Deepr does not differentiate queries and mutations. So, performing a mutation is just a matter of calling a method.
The query above will return:
{
"movie": {
"id": "cjrts72gy00ik01rv6eins4se"
}
}
Now that we have added a movie, let's retrieve it:
{
"movies=>": {
"get=>movie": {
"()": [{"id": "cjrts72gy00ik01rv6eins4se"}],
"=>": {"id": true, "title": true, "country": true}
}
}
}
This will return:
{
"movie": {
"id": "cjrts72gy00ik01rv6eins4se",
"title": "Avatar",
"country": "USA"
}
}
To modify a record, we can do this with:
{
"movies=>": {
"get=>movie": {
"()": [{"id": "cjrts72gy00ik01rv6eins4se"}],
"update=>": {
"()": [{"rating": 8.1}],
"=>": {"id": true}
}
}
}
}
Note how we use the key "update=>"
instead of "update"
to avoid creating an unnecessary "update"
key in the response:
{
"movie": {
"id": "cjrts72gy00ik01rv6eins4se
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论