GraphQL from the perspective of a Delphi developer
July 21, 2020
July 21, 2020
[SHOWTOGROUPS=4,20]
By now you probably know about Для просмотра ссылки Войдиили Зарегистрируйся, or at least you might have read or heard that name somewhere. Для просмотра ссылки Войди или Зарегистрируйся that “GraphQL is an open-source data Для просмотра ссылки Войди или Зарегистрируйся and Для просмотра ссылки Войди или Зарегистрируйся language for Для просмотра ссылки Войди или Зарегистрируйся, and a runtime for fulfilling queries with existing data”. If that doesn’t say much to you, or if you have read about GraphQL before but didn’t understand very well what it is, then this article is for you. Its purpose is to try – again – to explain what GraphQL is, its advantages and disadvantages, from the perspective of a Delphi (and also Для просмотра ссылки Войди или Зарегистрируйся) developer.
What is GraphQL?
There are plenty of articles explaining what GraphQL is. The Для просмотра ссылки Войдиили Зарегистрируйся, the Для просмотра ссылки Войди или Зарегистрируйся, tutorials Для просмотра ссылки Войди или Зарегистрируйся and Для просмотра ссылки Войди или Зарегистрируйся. So I will try to not be repetitive here and explain it my way, converting the points I was most confused of when I was learning about it. First of all:
Of course, then you have several GraphQL implementations, which are indeed libraries in several different languages like Для просмотра ссылки Войдиили Зарегистрируйся, Для просмотра ссылки Войди или Зарегистрируйся, Для просмотра ссылки Войди или Зарегистрируйся, that allow you to create, for example, servers that, through HTTP, allow clients to send such queries and get the response of such query execution in JSON format. But note that even that HTTP communication is not strictly specified. It’s just one of many ways to “execute” a GraphQL document (a text file containing a query in valid GraphQL language).
GraphQL is “strongly typed”
This is one key point of GraphQL. Whatever you are going to do with it, you always start from a “schema”, which specifies all the types available in the language. The following is an example of a GraphQL schema:
type Query {
human(id: Int): Human
}
type Human {
id: Int!
name: String!
homePlanet: String
height: Float
mass: Float
}
The above schema specifies two object types: Query and Human, the fields in each object type, and the type returned for each field. Fields can also have arguments (parameters), also with its specified type (human field in Query type has the parameter id of type Int).
If you are implementing a server that supports GraphQL, you have to define a schema first. If you are writing a client that sends GraphQL queries to a server, those queries must comply with the specified schema. You cannot create a query asking for a type that doesn’t exist. Or a field that doesn’t exist. Or even using a field parameter (argument) of a different data type than the specified.
It’s interesting to note that in a world that dynamic languages are so popular today (JavaScript being the main one), one of the key claims about GraphQL advantages is that it’s strongly typed – something I personally like, as a Delphi developer.
GraphQL documents (queries)
Once the GraphQL schema is defined, clients can write GraphQL documents (queries). In summary, a GraphQL query just lists the fields that we want the values for, and if such fields return objects, the fields of those objects, and on and on at any depth level you want. For example:
{
human(id: 1000) {
name
height
}
}
The query above asks for the value of human field of type Query (implicit by default because of its name), passing the value 1000 for the id parameter. Since human field returns an object of type Human, the query also asks for just fields name and height for such object.
If such query is sent via HTTP to a server implementing GraphQL, the server will execute the query and return its results. A possible result could be something like this:
{
"data": {
"human": {
"name": "Luke Skywalker",
"height": 1.72
}
}
}
You get what you asked for: the result of human field, and the name and height fields of the Human object. It’s also important to explain two things:
GraphQL and HTTP
GraphQL specification doesn’t say anything about HTTP. That really got me confused at the beginning, because I was reading all around about how GraphQL compares to REST, how it’s a new way to build APIs, etc. But the thing is GraphQL is not about HTTP, but only about the query language and how it should return results, in any format.
But of course, HTTP became the main way of executing GraphQL queries, and JSON end up being the most used format to return the results of such execution. The closest to a standard we have are some guidelines about Для просмотра ссылки Войдиили Зарегистрируйся, in the official GraphQL site.
In summary, there are no multiple endpoints: GraphQL queries are sent to a single URL endpoint, either directly in the URL in GET requests:
Для просмотра ссылки Войдиили Зарегистрируйся{{human(id:1000){name,height}}
or in a JSON document, in POST requests:
POST /graphql HTTP/1.1
Host: myapi
{
"query": "{{human(id:1000){name,height}}"
}
And the server response is usually a JSON document, as we saw above. It’s also interesting to note that if the GraphQL query is accepted, it always return an HTTP status code 200, even if the query execution fails. If there are errors, they appear inside the JSON document (error format is included in GraphQL specification):
{
"errors": [
{
"message": "Cannot query field \"homePlanet\" on type \"Human\"."
}
]
}
Why GraphQL?
Now that we have quickly covered what GraphQL is, it’s time to learn why it’s beginning to be so widely used.
There are several articles mentioning Для просмотра ссылки Войдиили Зарегистрируйся, explaining why Для просмотра ссылки Войди или Зарегистрируйся, directly Для просмотра ссылки Войди или Зарегистрируйся, listing reasons Для просмотра ссылки Войди или Зарегистрируйся and even Для просмотра ссылки Войди или Зарегистрируйся (despite the awful name – in my opinion – this last one is a nice article about GraphQL).
I will try to summarize what I think are the key reasons. I will also try to compare it with REST and specially with Для просмотра ссылки Войдиили Зарегистрируйся – a framework to build REST API servers using Delphi.
Clients choose what to fetch
In REST, support you want to retrieve an invoice you will do something like this:
GET /invoice/10
{
"id": 10,
"total": 152
}
Then, if you want to retrieve the customer of the invoice, you need another request:
GET /invoice/10/customer
{
"id": 115,
"name": "Joe Doe"
}
Of course, your REST server could return customer data inline in the first request, when invoice is request. But then, what if the client does not want customer data? The server will return more data than the client needs. In GraphQL you write the query asking just the data you want. Either without customer data:
{
invoice(10) {
id
total
}
}
or with customer data:
{
invoice(10) {
id
total
customer {
id
name
}
}
}
And you don’t have to modify your server for that, or create multiple endpoints. Developing client applications with GraphQL, specially mobile and web applications, is a breeze, and performs very well – in a single request you get all the data you need, and only the data you need.
On the other hand, your REST server could implement mechanisms to allow your client to better choose what it needs. That’s what XData does, for example, with the Для просмотра ссылки Войдиили Зарегистрируйся. When an invoice is request from the client, it comes with minimum customer information (just the id):
GET /invoice/10
{
"id": 10,
"total": 152,
"[email protected]": "customer(115)"
}
but if the client wants full customer information, he can just ask for it using $expand:
GET /invoice/10?$expand=customer
{
"id": 10,
"total": 152,
"customer": {
"id": 115,
"name": "John Doe"
}
}
When I first learned about GraphQL, my thought was: this might be an advantage in some situations, but if you are using a XData REST server, it’s not a big difference. With XData, there are ways to get all related (associated) information in one single server request (roundtrip).
[/SHOWTOGROUPS]
By now you probably know about Для просмотра ссылки Войди
What is GraphQL?
There are plenty of articles explaining what GraphQL is. The Для просмотра ссылки Войди
- GraphQL is NOT a framework or programming library;
- GraphQL is NOT a server application;
- GraphQL is NOT a database server or wrapper.
- GraphQL is a SPECIFICATION for a language and a runtime (Для просмотра ссылки Войди
или Зарегистрируйся).
Of course, then you have several GraphQL implementations, which are indeed libraries in several different languages like Для просмотра ссылки Войди
GraphQL is “strongly typed”
This is one key point of GraphQL. Whatever you are going to do with it, you always start from a “schema”, which specifies all the types available in the language. The following is an example of a GraphQL schema:
type Query {
human(id: Int): Human
}
type Human {
id: Int!
name: String!
homePlanet: String
height: Float
mass: Float
}
The above schema specifies two object types: Query and Human, the fields in each object type, and the type returned for each field. Fields can also have arguments (parameters), also with its specified type (human field in Query type has the parameter id of type Int).
If you are implementing a server that supports GraphQL, you have to define a schema first. If you are writing a client that sends GraphQL queries to a server, those queries must comply with the specified schema. You cannot create a query asking for a type that doesn’t exist. Or a field that doesn’t exist. Or even using a field parameter (argument) of a different data type than the specified.
It’s interesting to note that in a world that dynamic languages are so popular today (JavaScript being the main one), one of the key claims about GraphQL advantages is that it’s strongly typed – something I personally like, as a Delphi developer.
GraphQL documents (queries)
Once the GraphQL schema is defined, clients can write GraphQL documents (queries). In summary, a GraphQL query just lists the fields that we want the values for, and if such fields return objects, the fields of those objects, and on and on at any depth level you want. For example:
{
human(id: 1000) {
name
height
}
}
The query above asks for the value of human field of type Query (implicit by default because of its name), passing the value 1000 for the id parameter. Since human field returns an object of type Human, the query also asks for just fields name and height for such object.
If such query is sent via HTTP to a server implementing GraphQL, the server will execute the query and return its results. A possible result could be something like this:
{
"data": {
"human": {
"name": "Luke Skywalker",
"height": 1.72
}
}
}
You get what you asked for: the result of human field, and the name and height fields of the Human object. It’s also important to explain two things:
- The GraphQL query is NOT a JSON document, even though it looks like one. It’s a GraphQL query, with its specific syntax as defined by the specification.
- The result data IS a JSON document, and the way it is formatted is NOT in the specification. It could be a XML document or whatever other format.
GraphQL and HTTP
GraphQL specification doesn’t say anything about HTTP. That really got me confused at the beginning, because I was reading all around about how GraphQL compares to REST, how it’s a new way to build APIs, etc. But the thing is GraphQL is not about HTTP, but only about the query language and how it should return results, in any format.
But of course, HTTP became the main way of executing GraphQL queries, and JSON end up being the most used format to return the results of such execution. The closest to a standard we have are some guidelines about Для просмотра ссылки Войди
In summary, there are no multiple endpoints: GraphQL queries are sent to a single URL endpoint, either directly in the URL in GET requests:
Для просмотра ссылки Войди
or in a JSON document, in POST requests:
POST /graphql HTTP/1.1
Host: myapi
{
"query": "{{human(id:1000){name,height}}"
}
And the server response is usually a JSON document, as we saw above. It’s also interesting to note that if the GraphQL query is accepted, it always return an HTTP status code 200, even if the query execution fails. If there are errors, they appear inside the JSON document (error format is included in GraphQL specification):
{
"errors": [
{
"message": "Cannot query field \"homePlanet\" on type \"Human\"."
}
]
}
Why GraphQL?
Now that we have quickly covered what GraphQL is, it’s time to learn why it’s beginning to be so widely used.
There are several articles mentioning Для просмотра ссылки Войди
I will try to summarize what I think are the key reasons. I will also try to compare it with REST and specially with Для просмотра ссылки Войди
Clients choose what to fetch
In REST, support you want to retrieve an invoice you will do something like this:
GET /invoice/10
{
"id": 10,
"total": 152
}
Then, if you want to retrieve the customer of the invoice, you need another request:
GET /invoice/10/customer
{
"id": 115,
"name": "Joe Doe"
}
Of course, your REST server could return customer data inline in the first request, when invoice is request. But then, what if the client does not want customer data? The server will return more data than the client needs. In GraphQL you write the query asking just the data you want. Either without customer data:
{
invoice(10) {
id
total
}
}
or with customer data:
{
invoice(10) {
id
total
customer {
id
name
}
}
}
And you don’t have to modify your server for that, or create multiple endpoints. Developing client applications with GraphQL, specially mobile and web applications, is a breeze, and performs very well – in a single request you get all the data you need, and only the data you need.
On the other hand, your REST server could implement mechanisms to allow your client to better choose what it needs. That’s what XData does, for example, with the Для просмотра ссылки Войди
GET /invoice/10
{
"id": 10,
"total": 152,
"[email protected]": "customer(115)"
}
but if the client wants full customer information, he can just ask for it using $expand:
GET /invoice/10?$expand=customer
{
"id": 10,
"total": 152,
"customer": {
"id": 115,
"name": "John Doe"
}
}
When I first learned about GraphQL, my thought was: this might be an advantage in some situations, but if you are using a XData REST server, it’s not a big difference. With XData, there are ways to get all related (associated) information in one single server request (roundtrip).
[/SHOWTOGROUPS]