Merge pull request #5695 from consuldemocracy/graphql_docs
Update GraphQL documentation
This commit is contained in:
@@ -1,29 +0,0 @@
|
||||
require "net/http"
|
||||
|
||||
API_ENDPOINT = "https://demo.consuldemocracy.org/graphql".freeze
|
||||
|
||||
def make_request(query_string)
|
||||
uri = URI(API_ENDPOINT)
|
||||
uri.query = URI.encode_www_form(query: query_string.delete("\n").delete(" "))
|
||||
request = Net::HTTP::Get.new(uri)
|
||||
request[:accept] = "application/json"
|
||||
|
||||
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |https|
|
||||
https.request(request)
|
||||
end
|
||||
end
|
||||
|
||||
query = <<-GRAPHQL
|
||||
{
|
||||
proposal(id: 1) {
|
||||
id,
|
||||
title,
|
||||
public_created_at
|
||||
}
|
||||
}
|
||||
GRAPHQL
|
||||
|
||||
response = make_request(query)
|
||||
|
||||
puts "Response code: #{response.code}"
|
||||
puts "Response body: #{response.body}"
|
||||
@@ -1,68 +0,0 @@
|
||||
require "net/http"
|
||||
require "json"
|
||||
|
||||
API_ENDPOINT = "https://demo.consuldemocracy.org/graphql".freeze
|
||||
|
||||
def make_request(query_string)
|
||||
uri = URI(API_ENDPOINT)
|
||||
uri.query = URI.encode_www_form(query: query_string.delete("\n").delete(" "))
|
||||
request = Net::HTTP::Get.new(uri)
|
||||
request[:accept] = "application/json"
|
||||
|
||||
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |https|
|
||||
https.request(request)
|
||||
end
|
||||
end
|
||||
|
||||
def build_query(options = {})
|
||||
page_size = options[:page_size] || 25
|
||||
page_size_parameter = "first: #{page_size}"
|
||||
|
||||
page_number = options[:page_number] || 0
|
||||
after_parameter = page_number.positive? ? ", after: \"#{options[:next_cursor]}\"" : ""
|
||||
|
||||
<<-GRAPHQL
|
||||
{
|
||||
proposals(#{page_size_parameter}#{after_parameter}) {
|
||||
pageInfo {
|
||||
endCursor,
|
||||
hasNextPage
|
||||
},
|
||||
edges {
|
||||
node {
|
||||
id,
|
||||
title,
|
||||
public_created_at
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GRAPHQL
|
||||
end
|
||||
|
||||
page_number = 0
|
||||
next_cursor = nil
|
||||
proposals = []
|
||||
|
||||
loop do
|
||||
puts "> Requesting page #{page_number}"
|
||||
|
||||
query = build_query(page_size: 25, page_number: page_number, next_cursor: next_cursor)
|
||||
response = make_request(query)
|
||||
|
||||
response_hash = JSON.parse(response.body)
|
||||
page_info = response_hash["data"]["proposals"]["pageInfo"]
|
||||
has_next_page = page_info["hasNextPage"]
|
||||
next_cursor = page_info["endCursor"]
|
||||
proposal_edges = response_hash["data"]["proposals"]["edges"]
|
||||
|
||||
puts "\tHTTP code: #{response.code}"
|
||||
|
||||
proposal_edges.each do |edge|
|
||||
proposals << edge["node"]
|
||||
end
|
||||
|
||||
page_number += 1
|
||||
|
||||
break unless has_next_page
|
||||
end
|
||||
@@ -14,9 +14,11 @@
|
||||
* [Pagination](#pagination)
|
||||
* [Accessing several resources in a single request](#accessing-several-resources-in-a-single-request)
|
||||
* [Security limitations](#security-limitations)
|
||||
* [Example of too deep query](#example-of-too-deep-query)
|
||||
* [Example of too complex query](#example-of-too-complex-query)
|
||||
* [Example of a query which is too deep](#example-of-a-query-which-is-too-deep)
|
||||
* [Example of a query which is too complex](#example-of-a-query-which-is-too-complex)
|
||||
* [Code examples](#code-examples)
|
||||
* [Simple example](#simple-example)
|
||||
* [Example with pagination](#example-with-pagination)
|
||||
|
||||
## Characteristics
|
||||
|
||||
@@ -30,11 +32,11 @@
|
||||
|
||||
## GraphQL
|
||||
|
||||
The Consul Democracy API uses GraphQL [http://graphql.org](http://graphql.org), the [Ruby implementation](http://graphql-ruby.org/), to be specific. If you're not familiar with this kind of APIs, it's recommended to make some research about GraphQL before.
|
||||
The Consul Democracy API uses [GraphQL](http://graphql.org), specifically the [Ruby implementation](http://graphql-ruby.org/). If you're not familiar with this kind of APIs, we recommended you to check the [GraphQL official documentation](https://graphql.org/learn/).
|
||||
|
||||
One of the characteristics that differentiates a REST API from a GraphQL one is that with the last one it's possible for the client to build its own *custom queries*, so the server will only return information in which we're interested.
|
||||
One of the characteristics that differentiates a REST API from a GraphQL one is that with the latter one it's possible for the client to build its own *custom queries*, so the server will only return information in which we're interested.
|
||||
|
||||
GraphQL queries are written following a standard which resembles to JSON, for example:
|
||||
GraphQL queries are written following a format which resembles JSON. For example:
|
||||
|
||||
```graphql
|
||||
{
|
||||
@@ -56,10 +58,10 @@ Responses are formatted in JSON:
|
||||
"data": {
|
||||
"proposal": {
|
||||
"id": 1,
|
||||
"title": "Hacer las calles del centro de Madrid peatonales",
|
||||
"title": "Increase the amount of green spaces",
|
||||
"public_author": {
|
||||
"id": 2,
|
||||
"username": "electrocronopio"
|
||||
"username": "abetterworld"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,7 +79,7 @@ Following [the official recommendations](http://graphql.org/learn/serving-over-h
|
||||
|
||||
### Supported clients
|
||||
|
||||
Because it's an API that works through HTTP, any tool capable of making this kind of requests is capable of querying the API.
|
||||
Since this is an API that works through HTTP, any tool capable of making this kind of requests is capable of querying the API.
|
||||
|
||||
This section presents a few examples about how to make requests using:
|
||||
|
||||
@@ -87,41 +89,41 @@ This section presents a few examples about how to make requests using:
|
||||
|
||||
#### GraphiQL
|
||||
|
||||
[GraphiQL](https://github.com/graphql/graphiql) is a browser interface for making queries against a GraphQL API. It's also an additional source of documentation. It's deployed in the route `/graphiql` and it's the best way to get familiar with GraphQL-based APIs.
|
||||
[GraphiQL](https://github.com/graphql/graphiql) is a browser interface for making queries against a GraphQL API. It's also an additional source of documentation. Consul Democracy uses the [graphiql-rails](https://github.com/rmosolgo/graphiql-rails) to access this interface at `/graphiql`; it's the best way to get familiar with GraphQL-based APIs.
|
||||
|
||||

|
||||

|
||||
|
||||
It has three main panels:
|
||||
It's got three main panels:
|
||||
|
||||
* The left panel is used to write the query.
|
||||
* The central panel shows the result of the request.
|
||||
* The right panel (occultable) shows a documentation autogenerated from the models and fields exposed in the API.
|
||||
* The right panel (hideable) shows a documentation autogenerated from the models and fields exposed in the API.
|
||||
|
||||
#### Postman
|
||||
|
||||
Example of `GET` request, with the query as part of the *query string*:
|
||||
Here's an example of a `GET` request, with the query as part of the *query string*:
|
||||
|
||||

|
||||

|
||||
|
||||
Example of `POST` request, with the query as part of the *body* and encoded as `application/json`:
|
||||
And here's an example of a `POST` request, with the query as part of the *body* and encoded as `application/json`:
|
||||
|
||||

|
||||

|
||||
|
||||
The query must be located inside a valid JSON document, as the value of the `"query"` key:
|
||||
|
||||

|
||||

|
||||
|
||||
#### HTTP libraries
|
||||
|
||||
Sure you can use any HTTP library available for most programming languages.
|
||||
You can use any of the HTTP libraries available for most programming languages.
|
||||
|
||||
**IMPORTANT**: Due to security protocols from the Madrid City Council servers, it's necessary to include a *User Agent* header from a web browser so the request is not rejected. For example:
|
||||
**IMPORTANT**: Some servers might use security protocols that will make it necessary to include a *User Agent* header from a web browser so the request is not rejected. For example:
|
||||
|
||||
`User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36`
|
||||
`User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/116.0`
|
||||
|
||||
## Available information
|
||||
|
||||
The [config/api.yml](../../config/api.yml) file contains a complete list of all the models (and their attributes) which are currently being exposed in the API.
|
||||
The `app/graphql/types/` folder contains a complete list of all the models (and their attributes) which are currently being exposed in the API.
|
||||
|
||||
The models are the following:
|
||||
|
||||
@@ -160,7 +162,7 @@ Response:
|
||||
"data": {
|
||||
"proposal": {
|
||||
"id": 2,
|
||||
"title": "Crear una zona cercada para perros en Las Tablas",
|
||||
"title": "Create a dog-friendly area near the beach",
|
||||
"comments_count": 10
|
||||
}
|
||||
}
|
||||
@@ -190,12 +192,12 @@ Response:
|
||||
"edges": [
|
||||
{
|
||||
"node": {
|
||||
"title": "ELIMINACION DE ZONA APARCAMIENTO EXCLUSIVO FUNCIONARIOS EN MADRID"
|
||||
"title": "Bus stop near the school"
|
||||
}
|
||||
},
|
||||
{
|
||||
"node": {
|
||||
"title": "iluminación de zonas deportivas"
|
||||
"title": "Improve the lighting in the football stadium"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -206,7 +208,7 @@ Response:
|
||||
|
||||
#### Pagination
|
||||
|
||||
The maximum (and default) number of records that each page contains is set to 25. For navigating through the different pages it's necessary to request also information relative to the `endCursor`:
|
||||
The maximum (and default) number of records that each page contains is set to 25. In order to navigate through the different pages, it's necessary to request `endCursor` information:
|
||||
|
||||
```graphql
|
||||
{
|
||||
@@ -243,7 +245,7 @@ The response:
|
||||
}
|
||||
```
|
||||
|
||||
To retrieve the next page, you have to pass as a parameter the cursor received in the previous request, and so on:
|
||||
To retrieve the next page, pass the cursor received in the previous request as a parameter:
|
||||
|
||||
```graphql
|
||||
{
|
||||
@@ -289,7 +291,7 @@ This query requests information about several models in a single request: `Propo
|
||||
|
||||
## Security limitations
|
||||
|
||||
Allowing a client to customize queries is a major risk factor. If too complex queries were allowed, it would be possible to perform a DoS attack against the server.
|
||||
Allowing a client to customize queries is a major risk factor. If queries that are too complex were allowed, it would be possible to perform a DoS attack against the server.
|
||||
|
||||
There are three main mechanisms to prevent such abuses:
|
||||
|
||||
@@ -297,7 +299,7 @@ There are three main mechanisms to prevent such abuses:
|
||||
* Limit the maximum depth of the queries
|
||||
* Limit the amount of information that is possible to request in a query
|
||||
|
||||
### Example of too deep query
|
||||
### Example of a query which is too deep
|
||||
|
||||
The maximum depth of queries is currently set at 8. Deeper queries (such as the following) will be rejected:
|
||||
|
||||
@@ -338,9 +340,9 @@ The response will look something like this:
|
||||
}
|
||||
```
|
||||
|
||||
### Example of too complex query
|
||||
### Example of a query which is too complex
|
||||
|
||||
The main risk factor is when multiple collections of resources are requested in the same query. The maximum number of collections that can appear in the same query is limited to 2. The following query requests information from the `users`, `debates` and `proposals` collections, so it will be rejected:
|
||||
The main risk factor is the option to request multiple collections of resources in the same query. The maximum number of collections that can appear in the same query is limited to 2. The following query requests information from the `users`, `debates` and `proposals` collections, so it will be rejected:
|
||||
|
||||
```graphql
|
||||
{
|
||||
@@ -372,12 +374,6 @@ The response will look something like this:
|
||||
```json
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"message": "Query has complexity of 3008, which exceeds max complexity of 2500"
|
||||
},
|
||||
{
|
||||
"message": "Query has complexity of 3008, which exceeds max complexity of 2500"
|
||||
},
|
||||
{
|
||||
"message": "Query has complexity of 3008, which exceeds max complexity of 2500"
|
||||
}
|
||||
@@ -416,9 +412,9 @@ The response:
|
||||
"edges": [
|
||||
{
|
||||
"node": {
|
||||
"title": "Empadronamiento necesario para la admisión en GoFit Vallehermoso",
|
||||
"title": "Make a discount to locals in sports centers",
|
||||
"geozone": {
|
||||
"name": "Chamberí"
|
||||
"name": "South area"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -431,4 +427,113 @@ The response:
|
||||
|
||||
## Code examples
|
||||
|
||||
The [doc/api/examples](https://github.com/consuldemocracy/consuldemocracy/tree/master/doc/api/examples/ruby) directory contains examples of code to access the API.
|
||||
### Simple example
|
||||
|
||||
Here's a simple example of code accessing the Consul Democracy demo API:
|
||||
|
||||
```ruby
|
||||
require "net/http"
|
||||
|
||||
API_ENDPOINT = "https://demo.consuldemocracy.org/graphql".freeze
|
||||
|
||||
def make_request(query_string)
|
||||
uri = URI(API_ENDPOINT)
|
||||
uri.query = URI.encode_www_form(query: query_string)
|
||||
request = Net::HTTP::Get.new(uri)
|
||||
request[:accept] = "application/json"
|
||||
|
||||
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |https|
|
||||
https.request(request)
|
||||
end
|
||||
end
|
||||
|
||||
query = <<-GRAPHQL
|
||||
{
|
||||
proposal(id: 1) {
|
||||
id,
|
||||
title,
|
||||
public_created_at
|
||||
}
|
||||
}
|
||||
GRAPHQL
|
||||
|
||||
response = make_request(query)
|
||||
|
||||
puts "Response code: #{response.code}"
|
||||
puts "Response body: #{response.body}"
|
||||
```
|
||||
|
||||
### Example with pagination
|
||||
|
||||
And here is a more complex example using pagination, once again accessing the Consul Democracy demo API:
|
||||
|
||||
```ruby
|
||||
require "net/http"
|
||||
require "json"
|
||||
|
||||
API_ENDPOINT = "https://demo.consuldemocracy.org/graphql".freeze
|
||||
|
||||
def make_request(query_string)
|
||||
uri = URI(API_ENDPOINT)
|
||||
uri.query = URI.encode_www_form(query: query_string)
|
||||
request = Net::HTTP::Get.new(uri)
|
||||
request[:accept] = "application/json"
|
||||
|
||||
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |https|
|
||||
https.request(request)
|
||||
end
|
||||
end
|
||||
|
||||
def build_query(options = {})
|
||||
page_size = options[:page_size] || 25
|
||||
page_size_parameter = "first: #{page_size}"
|
||||
|
||||
page_number = options[:page_number] || 0
|
||||
after_parameter = page_number.positive? ? ", after: \"#{options[:next_cursor]}\"" : ""
|
||||
|
||||
<<-GRAPHQL
|
||||
{
|
||||
proposals(#{page_size_parameter}#{after_parameter}) {
|
||||
pageInfo {
|
||||
endCursor,
|
||||
hasNextPage
|
||||
},
|
||||
edges {
|
||||
node {
|
||||
id,
|
||||
title,
|
||||
public_created_at
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GRAPHQL
|
||||
end
|
||||
|
||||
page_number = 0
|
||||
next_cursor = nil
|
||||
proposals = []
|
||||
|
||||
loop do
|
||||
puts "> Requesting page #{page_number}"
|
||||
|
||||
query = build_query(page_size: 25, page_number: page_number, next_cursor: next_cursor)
|
||||
response = make_request(query)
|
||||
|
||||
response_hash = JSON.parse(response.body)
|
||||
page_info = response_hash["data"]["proposals"]["pageInfo"]
|
||||
has_next_page = page_info["hasNextPage"]
|
||||
next_cursor = page_info["endCursor"]
|
||||
proposal_edges = response_hash["data"]["proposals"]["edges"]
|
||||
|
||||
puts "\tHTTP code: #{response.code}"
|
||||
|
||||
proposal_edges.each do |edge|
|
||||
proposals << edge["node"]
|
||||
end
|
||||
|
||||
page_number += 1
|
||||
|
||||
break unless has_next_page
|
||||
end
|
||||
```
|
||||
|
||||
@@ -17,24 +17,26 @@
|
||||
* [Ejemplo de consulta demasiado profunda](#ejemplo-de-consulta-demasiado-profunda)
|
||||
* [Ejemplo de consulta demasiado compleja](#ejemplo-de-consulta-demasiado-compleja)
|
||||
* [Ejemplos de código](#ejemplos-de-codigo)
|
||||
* [Ejemplo sencillo](#ejemplo-sencillo)
|
||||
* [Ejemplo con paginación](#ejemplo-con-paginacion)
|
||||
|
||||
<h2 id="caracteristicas">Características</h2>
|
||||
|
||||
* API de sólo lectura
|
||||
* Acceso público, sin autenticación
|
||||
* Usa GraphQL por debajo
|
||||
* El tamaño máximo (y por defecto) de página está establecido a 25
|
||||
* La profundiad máxima de las consultas es de 8 niveles
|
||||
* Usa GraphQL:
|
||||
* El tamaño máximo (y por defecto) de registros por página es 25
|
||||
* La profundidad máxima de las consultas es de 8 niveles
|
||||
* Como máximo se pueden solicitar 2 colecciones en una misma consulta
|
||||
* Soporte para peticiones GET (consulta dentro del *query string*) y POST (consulta dentro del *body*, como `application/json` o `application/graphql`).
|
||||
|
||||
## GraphQL
|
||||
|
||||
La API de Consul Democracy utiliza GraphQL [http://graphql.org](https://graphql.org), en concreto la [implementación en Ruby](http://graphql-ruby.org/). Si no estás familiarizado con este tipo de APIs, es recomendable investigar un poco sobre GraphQL previamente.
|
||||
La API de Consul Democracy utiliza [GraphQL](https://graphql.org), en concreto la [implementación en Ruby](http://graphql-ruby.org/). Si no estás familiarizado con este tipo de APIs, te recomendamos consultar la [documentación oficial de GraphQL](https://graphql.org/learn/).
|
||||
|
||||
Una de las caracteríticas que diferencian una API REST de una GraphQL es que con esta última es posible construir *consultas personalizadas*, de forma que el servidor nos devuelva únicamente la información en la que estamos interesados.
|
||||
Una de las características que diferencian una API REST de una GraphQL es que con esta última es posible construir *consultas personalizadas*, de forma que el servidor nos devuelva únicamente la información en la que estamos interesados.
|
||||
|
||||
Las consultas en GraphQL están escritas siguiendo un estándar que presenta ciertas similitudes con el formato JSON, por ejemplo:
|
||||
Las consultas en GraphQL están escritas siguiendo un formato que presenta ciertas similitudes con el formato JSON, por ejemplo:
|
||||
|
||||
```graphql
|
||||
{
|
||||
@@ -56,10 +58,10 @@ Las respuestas son en formato JSON:
|
||||
"data": {
|
||||
"proposal": {
|
||||
"id": 1,
|
||||
"title": "Hacer las calles del centro de Madrid peatonales",
|
||||
"title": "Aumentar la cantidad de zonas verdes",
|
||||
"public_author": {
|
||||
"id": 2,
|
||||
"username": "electrocronopio"
|
||||
"username": "unmundomejor"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +81,7 @@ Siguiendo las [directrices oficiales](http://graphql.org/learn/serving-over-http
|
||||
|
||||
Al ser una API que funciona a través de HTTP, cualquier herramienta capaz de realizar este tipo de peticiones resulta válida.
|
||||
|
||||
Esta sección contiene unos pequeños ejemplos sobre cómo hacer las peticiones a través de:
|
||||
Esta sección contiene algunos ejemplos sobre cómo hacer las peticiones a través de:
|
||||
|
||||
* GraphiQL
|
||||
* Extensiones de Chrome como Postman
|
||||
@@ -87,9 +89,9 @@ Esta sección contiene unos pequeños ejemplos sobre cómo hacer las peticiones
|
||||
|
||||
#### GraphiQL
|
||||
|
||||
[GraphiQL](https://github.com/graphql/graphiql) es una interfaz de navegador para realizar consultas a una API GraphQL, así como una fuente adicional de documentación. Está desplegada en la ruta `/graphiql` y es la mejor forma de familiarizarse una API basada en GraphQL.
|
||||
[GraphiQL](https://github.com/graphql/graphiql) es una interfaz de navegador para realizar consultas a una API GraphQL, así como una fuente adicional de documentación. Consul Democracy utiliza la gema [graphiql-rails](https://github.com/rmosolgo/graphiql-rails) para acceder a esta interfaz en la ruta `/graphiql`; esta es la mejor forma de familiarizarse con una API basada en GraphQL.
|
||||
|
||||

|
||||

|
||||
|
||||
Tiene tres paneles principales:
|
||||
|
||||
@@ -101,27 +103,27 @@ Tiene tres paneles principales:
|
||||
|
||||
Ejemplo de petición `GET`, con la consulta como parte del *query string*:
|
||||
|
||||

|
||||

|
||||
|
||||
Ejemplo de petición `POST`, con la consulta como parte del *body* y codificada como `application/json`:
|
||||
|
||||

|
||||

|
||||
|
||||
La consulta debe estar ubicada en un documento JSON válido, como valor de la clave `"query"`:
|
||||
|
||||

|
||||

|
||||
|
||||
<h4 id="librerias-http">Librerías HTTP</h4>
|
||||
|
||||
Por supuesto es posible utilizar cualquier librería HTTP de lenguajes de programación.
|
||||
Es posible utilizar cualquier librería HTTP de lenguajes de programación.
|
||||
|
||||
**IMPORTANTE**: Debido a los protocolos de seguridad de los servidores del Ayuntamiento de Madrid, es necesario incluir un *User Agent* perteneciente a un navegador para que la petición no sea descartada. Por ejemplo:
|
||||
**IMPORTANTE**: Algunos servidores podrían tener protocolos de seguridad que hagan necesario incluir un *User Agent* perteneciente a un navegador para que la petición no sea descartada. Por ejemplo:
|
||||
|
||||
`User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36`
|
||||
`User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/116.0`
|
||||
|
||||
<h2 id="informacion-disponible">Información disponible</h2>
|
||||
|
||||
El fichero [config/api.yml](../../config/api.yml) contiene una lista completa de los modelos (y sus campos) que están expuestos actualmente en la API.
|
||||
El directorio `app/graphql/types/` contiene una lista completa de los modelos (y sus campos) que están expuestos actualmente en la API.
|
||||
|
||||
La lista de modelos es la siguiente:
|
||||
|
||||
@@ -160,7 +162,7 @@ Respuesta:
|
||||
"data": {
|
||||
"proposal": {
|
||||
"id": 2,
|
||||
"title": "Crear una zona cercada para perros en Las Tablas",
|
||||
"title": "Crear una zona cercada para perros cerca de la playa",
|
||||
"comments_count": 10
|
||||
}
|
||||
}
|
||||
@@ -190,12 +192,12 @@ Respuesta:
|
||||
"edges": [
|
||||
{
|
||||
"node": {
|
||||
"title": "ELIMINACION DE ZONA APARCAMIENTO EXCLUSIVO FUNCIONARIOS EN MADRID"
|
||||
"title": "Parada de autobús cerca del colegio"
|
||||
}
|
||||
},
|
||||
{
|
||||
"node": {
|
||||
"title": "iluminación de zonas deportivas"
|
||||
"title": "Mejorar la iluminación de zonas deportivas"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -206,7 +208,7 @@ Respuesta:
|
||||
|
||||
<h4 id="paginacion">Paginación</h4>
|
||||
|
||||
Actualmente el número máximo (y por defecto) de elementos que se devuelven en cada página está establecido a 25. Para poder navegar por las distintas páginas es necesario solicitar además información relativa al `endCursor`:
|
||||
Actualmente el número máximo (y por defecto) de elementos que se devuelven en cada página está establecido a 25. Para poder navegar por las distintas páginas, es necesario solicitar además información relativa al `endCursor`:
|
||||
|
||||
```graphql
|
||||
{
|
||||
@@ -340,7 +342,7 @@ La respuesta obtenida tendrá el siguiente aspecto:
|
||||
|
||||
### Ejemplo de consulta demasiado compleja
|
||||
|
||||
El principal factor de riesgo se da cuando se solicitan varias colecciones de recursos en una misma consulta. El máximo número de colecciones que pueden aparecer en una misma consulta está limitado a 2. La siguiente consulta solicita información de las colecciónes `users`, `debates` y `proposals`, así que será rechazada:
|
||||
El principal factor de riesgo se da cuando se solicitan varias colecciones de recursos en una misma consulta. El máximo número de colecciones que pueden aparecer en una misma consulta está limitado a 2. La siguiente consulta solicita información de las colecciones `users`, `debates` y `proposals`, así que será rechazada:
|
||||
|
||||
```graphql
|
||||
{
|
||||
@@ -372,12 +374,6 @@ La respuesta obtenida tendrá el siguiente aspecto:
|
||||
```json
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"message": "Query has complexity of 3008, which exceeds max complexity of 2500"
|
||||
},
|
||||
{
|
||||
"message": "Query has complexity of 3008, which exceeds max complexity of 2500"
|
||||
},
|
||||
{
|
||||
"message": "Query has complexity of 3008, which exceeds max complexity of 2500"
|
||||
}
|
||||
@@ -385,7 +381,7 @@ La respuesta obtenida tendrá el siguiente aspecto:
|
||||
}
|
||||
```
|
||||
|
||||
No obstante sí que es posible solicitar información perteneciente a más de dos modelos en una única consulta, siempre y cuando no se intente acceder a la colección completa. Por ejemplo, la siguiente consulta que accede a los modelos `User`, `Proposal` y `Geozone` es válida:
|
||||
No obstante, sí que es posible solicitar información perteneciente a más de dos modelos en una única consulta, siempre y cuando no se intente acceder a la colección completa. Por ejemplo, la siguiente consulta que accede a los modelos `User`, `Proposal` y `Geozone` es válida:
|
||||
|
||||
```graphql
|
||||
{
|
||||
@@ -416,9 +412,9 @@ La respuesta:
|
||||
"edges": [
|
||||
{
|
||||
"node": {
|
||||
"title": "Empadronamiento necesario para la admisión en GoFit Vallehermoso",
|
||||
"title": "Descuento para empadronados en los centros deportivos",
|
||||
"geozone": {
|
||||
"name": "Chamberí"
|
||||
"name": "Zona sur"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -431,4 +427,113 @@ La respuesta:
|
||||
|
||||
<h2 id="ejemplos-de-codigo">Ejemplos de código</h2>
|
||||
|
||||
El directorio [doc/api/examples](https://github.com/consuldemocracy/consuldemocracy/tree/master/doc/api/examples/ruby) contiene ejemplos de código para acceder a la API.
|
||||
### Ejemplo sencillo
|
||||
|
||||
Este es un ejemplo sencillo de código accediendo a la API de la demo de Consul Democracy:
|
||||
|
||||
```ruby
|
||||
require "net/http"
|
||||
|
||||
API_ENDPOINT = "https://demo.consuldemocracy.org/graphql".freeze
|
||||
|
||||
def make_request(query_string)
|
||||
uri = URI(API_ENDPOINT)
|
||||
uri.query = URI.encode_www_form(query: query_string)
|
||||
request = Net::HTTP::Get.new(uri)
|
||||
request[:accept] = "application/json"
|
||||
|
||||
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |https|
|
||||
https.request(request)
|
||||
end
|
||||
end
|
||||
|
||||
query = <<-GRAPHQL
|
||||
{
|
||||
proposal(id: 1) {
|
||||
id,
|
||||
title,
|
||||
public_created_at
|
||||
}
|
||||
}
|
||||
GRAPHQL
|
||||
|
||||
response = make_request(query)
|
||||
|
||||
puts "Response code: #{response.code}"
|
||||
puts "Response body: #{response.body}"
|
||||
```
|
||||
|
||||
<h3 id="ejemplo-con-paginacion">Ejemplo con paginación</h3>
|
||||
|
||||
Y este es un ejemplo un tanto más complejo usando paginación, una vez más accediendo a la API de la demo de Consul Democracy:
|
||||
|
||||
```ruby
|
||||
require "net/http"
|
||||
require "json"
|
||||
|
||||
API_ENDPOINT = "https://demo.consuldemocracy.org/graphql".freeze
|
||||
|
||||
def make_request(query_string)
|
||||
uri = URI(API_ENDPOINT)
|
||||
uri.query = URI.encode_www_form(query: query_string)
|
||||
request = Net::HTTP::Get.new(uri)
|
||||
request[:accept] = "application/json"
|
||||
|
||||
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |https|
|
||||
https.request(request)
|
||||
end
|
||||
end
|
||||
|
||||
def build_query(options = {})
|
||||
page_size = options[:page_size] || 25
|
||||
page_size_parameter = "first: #{page_size}"
|
||||
|
||||
page_number = options[:page_number] || 0
|
||||
after_parameter = page_number.positive? ? ", after: \"#{options[:next_cursor]}\"" : ""
|
||||
|
||||
<<-GRAPHQL
|
||||
{
|
||||
proposals(#{page_size_parameter}#{after_parameter}) {
|
||||
pageInfo {
|
||||
endCursor,
|
||||
hasNextPage
|
||||
},
|
||||
edges {
|
||||
node {
|
||||
id,
|
||||
title,
|
||||
public_created_at
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GRAPHQL
|
||||
end
|
||||
|
||||
page_number = 0
|
||||
next_cursor = nil
|
||||
proposals = []
|
||||
|
||||
loop do
|
||||
puts "> Requesting page #{page_number}"
|
||||
|
||||
query = build_query(page_size: 25, page_number: page_number, next_cursor: next_cursor)
|
||||
response = make_request(query)
|
||||
|
||||
response_hash = JSON.parse(response.body)
|
||||
page_info = response_hash["data"]["proposals"]["pageInfo"]
|
||||
has_next_page = page_info["hasNextPage"]
|
||||
next_cursor = page_info["endCursor"]
|
||||
proposal_edges = response_hash["data"]["proposals"]["edges"]
|
||||
|
||||
puts "\tHTTP code: #{response.code}"
|
||||
|
||||
proposal_edges.each do |edge|
|
||||
proposals << edge["node"]
|
||||
end
|
||||
|
||||
page_number += 1
|
||||
|
||||
break unless has_next_page
|
||||
end
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user