Skip to content

Instantly share code, notes, and snippets.

@jrub
Last active August 29, 2015 14:17
Show Gist options
  • Save jrub/8707031fb834d80a7828 to your computer and use it in GitHub Desktop.
Save jrub/8707031fb834d80a7828 to your computer and use it in GitHub Desktop.
Feedback recopilado durante el #ZgzAppStore sobre las APIs Open Data del Ayuntamiento de Zaragoza

Feedback APIs Ayto Zgz

Web municipal

http://www.zaragoza.es/ciudad/actividades/

  • Bug en la web: das a Próximos 7 dias. En la siguiente ventana, das a la pestaña "todo", y no cambia total de eventos, se queda fijo en 7 dias aunque cambia la pestaña (ver URL, concatena el parámetro "rango" sin más)
  • en la web, sale todo ordenado por lastModified, por tanto una correción o modificación del evento hace que suba el evento arriba. No tiene mucho sentido. Yo si tuviera permisos de acceso para crear eventos, lo haría continuamente para promocionar mi evento al primero de la lista en mi categoría.
  • Tras entrar a la sección "Fiestas Locales", aparece una nueva sección: JUVENIL
  • Cambiar el título de http://www.zaragoza.es/docs-api/ (Swagger UI) a algo más atractivo
  • En https://www.zaragoza.es/ciudad/risp/index_Api el literal "comporta sus datos" (en vez de Comparta)
  • Cifrado de la web obsoleto e inseguro. Ver mensaje de Google Chrome al clicar el candado en (https://www.zaragoza.es/ciudad/risp/buscar_Aplicacion):
Your connection to www.zaragoza.es is encrypted with obsolete cryptography. However, this page includes other resources which are not secure. These resources can be viewed by others while in transit, and can be modified by an attacker to change the behavior of the page.
 
The connection uses TLS 1.0.

The connection is encrypted using AES_256_CBC, with SHA1 for message authentication and RSA as the key exchange mechanism.

API SOLR

  • SOLR devuelve ID con acto-id, y en el API REST eso corresponde a id (sin acto)
  • fechaInicio_dt (pidiendo día 07, sale 06, por ser GMT): "2015-03-06T23:00:00Z", (es GMT)
  • documentar que hay que pasar "rows" para que devuelva el total del numCount en vez de un rows=10 que devuelve por defecto
  • descripcion_t suele contener la información de lugar_t, pero no siempre (homogeneizar tanto en solr como con las otras apis)
  • El tema de las consultas FIQL es interesante pero el RFC no pasó a estándar y está obsoleto en 2008. Siete años depués... ¿igual es el momento de buscar alternativas mejores? :-D

### API REST

### API SPARQL

  • ¿se puede hacer que devuelva los objetos como el API SOLR en cuanto a no tener que acceder a "title.value"? (y englobado las dos apis en el mismo objeto, sea "bindings" -sparql- o "docs" -solr). Es decir, dar coherencia a las dos APIs para que devuelvan exactamente la misma estructura JSON.
  • listado de los prefijos (PREFIX) cargados por defecto, no está documentado

Común a todas las APIs

  • se devuelve contenido formateado en HTML en muchos campos. Es "de mala educación" ;-) y además no hay nada que identifique qué campo va a devolver texto o HTML, lo cual es peor todavía.
  • Para que las APIs sean útiles para los reutilizadores, tienen que ser coherentes entre ellas (compartir todos los nombres de parámetros que devuelven, por ejemplo, y su contenido obviamente)
  • No puede haber peticiones sin documentar (lista de temas/subtemas en el API Rest, por ejemplo). Si todas las APIs funcionaran "como uno espera", esto sería menos grave... pero el hecho de que han ido evolucionando a ritmos diferentes, cubriendo necesidades diferentes, y el hecho de enfocarse a cubrir la necesidad de una web de dos décadas, aún se nota a la hora de usarlas. Por eso destaco el, al menos, que haya coherencia entre ellas y que estén bien documentadas. Van por buen camino, pero tal cual están ahora hay casos en los que no se diferencia mucho de "minar datos a mano", porque el reutilizador tiene que ir descifrando el funcionamiento del API.
  • Con el tema de cambiar APIs y por tanto "joder" a reutilizadores que ya las estén usando... quizás haya que empezar a implementar VERSIONADO de APIs... Aquí por ejemplo hay un articulillo, aunque ya viejo (2011) de Mark Nottingham, miembro del W3C (el que redactó el RFC del lenguaje de consultas FIQL que usáis en el API SOLR) https://www.mnot.net/blog/2011/10/25/web_api_versioning_smackdown O por ejemplo, cómo documenta Github los cambios de su API https://developer.github.com/v3/versions/

Ejemplos de datos mal estructurados en las APIs

  • Me repito una vez más: devolver HTML NO ES REUTILIZABLE. Sirve si te vas a hacer una web, no si quieres publicar un API. Un API sólamente debe contener datos estructurados, NUNCA JAMÁS texto libre.
  • El gobierno de UK está haciendo un gran trabajo con el Open Data, podemos aprender de ellos:
  • https://www.gov.uk/service-manual/technology/open-data.html
  • Aquí, explican como HTML puede ser un formato adecuado para "written reports" (nunca .doc), pero para datos estructurados, siempre un formato como JSON o al menos XML: https://www.gov.uk/service-manual/user-centred-design/choosing-appropriate-formats
  • Esto: "price": "Entrada gratuita" no sirve para nada a un reutilizador. ¿Y si lo queremos internacionalizar y mostrar en otro idioma? ¿Y si no queremos pintar ese texto sino una representación gráfica del dato?
  • Esto también es un error: "datos": "<a href=\"http://www.zaragoza.es/pgou/edih/sanagustinplazaconvento.pdf\" class=\"pdf\">Interés Un link no es un dato estructurado. Una URI sí lo es. Si se obliga al reutilizador a saber que ahí viene un elemento HTML (un href), entonces ya tiene que parsearlo, y ya no hay casi diferencia con hacer a mano un scraper y minar los datos con pico y pala.
  • Otro ejemplo: "horario": "Cerrado hasta nuevo aviso.\r\n\r\nMartes a sábado de 10 a 14h y 17 a 21h Imagina que no quiero mostrarlo, sino poner un botón que se integra con Google Calendar (o .ical en general) y al clicarlo añada ese evento al calendario del usuario. Efectivamente, al devolver un texto libre, un dato no estructurado, no sirve. Un ejemplo de cómo podría ser útil para los reutilizadores:
"horary": {
  "monday": [
    {"from": "08:00", "to": "17:00"},
  ],
  "tuesday": [
    {"from": "08:00", "to": "17:00"},
  ],
  ...
}
@gimenete
Copy link

Lo que has puesto de google calendar lo cambiaría por:

Imagina que quiero mostrar de diferente color aquellos lugares que en el momento actual estén abiertos, o que quiero comparar la agenda del usuario con el horario de los monumentos para saber cuándo podría acudir en un futuro.

Me parece que queda más claro explicando que tal como están los datos no se pueden hacer cálculos con ellos.

Pasa lo mismo con muchos campos. Con los precios por ejemplo. Si el API devuelve Entrada gratuita tengo que hacer un gran esfuerzo para que mi app entienda eso, donde podría simplemente poner "precio": 0. Con Entrada gratuita mi app no entiende cuánto vale, y tengo que hacer esfuerzos adicionales para traducir el texto si mi app está en varias idiomas. Y si en vez de Entrada gratuita otro día un funcionario que introduce datos pone Gratis ya mi app vuelve a no poder entender nada. Lo ideal sería tener datos estructurados y datos puros. Ejemplo para precios:

"price": {
  "regular": 3,
  "student": 2,
  "retired": 0,
  "unemployed": 0,
  "other-discounts": true,
}

En este ejemplo sería ideal que regular (precio normal) estuviera siempre presente y el resto fueran opcionales por ejemplo. Así se podría hacer una app que ordenara por precio, o que te dijera los que son gratis, o que te mostrara sólo el precio para estudiante si dices que eres estudiante,... En fin, mil posibilidades, pero con lo que hay la aplicación no puede hacer nada medianamente inteligente. Ejemplo:

"price": "<em>Entrada</em>: 3 euros\r\n<em>Tarifas reducidas para grupos y estudiantes</em>: 2 euros.\r\n<em>Gratuito</em>: Mayores de 65 años, desempleados, periodistas acreditados, monitores acompañantes y responsables de grupos de escolares, miembros del ICOM, Asociación de Críticos de Arte, niños menores de 8 años.\r\n<em>Entrada conjunta a los espacios de la Ruta de Caesaraugusta</em>:Foro, Termas Públicas, Puerto Fluvial y Teatro: 7 euros\r\n\r\nEntrada incluida en la Zaragoza Card",

Es imposible que la app entienda esa información. Lo único que puede hacer es mostrarla al usuario, pero no es capaz de procesar, manipular o utilizar esos datos más allá de mostrarlos sin hacer nada "inteligente".

Para matrícula de honor habría que devolver algo así:

"price": {
  "fares": {
    "regular": {
      "amount": 3
    },
    "groups": {
      "amount": 2,
      "min-size": 8,
    },
    "students": {
      "amount": 2,
    },
    "retired": {
      "amount": 0,
    },
    "guide": {
      "amount": 0,
    },
    "kids": {
      "amount": 0,
      "max-age": 8,
    },
    "unemployed": {
      "amount": 0,
    },
    "routes": [
      {
      "name": "Ruta de Caesaraugusta",
      "id": "id-de-la-ruta",
      "amount": 7,
      }
    ]
  }
  "zaragoza-card": true,
}

@virtor
Copy link

virtor commented Mar 26, 2015

Hola, soy uno de los técnicos de la web municipal y antes de empezar los comentarios, queríamos transmitiros desde todo el equipo de la web que vuestras aportaciones son muy valiosas para tratar de mejorar la publicación de los conjuntos de datos.

@jrub

Web municipal

  • SOLUCIONADO Bug en la web: das a Próximos 7 dias. En la siguiente ventana, das a la pestaña "todo", y no cambia total de eventos, se queda fijo en 7 dias aunque cambia la pestaña (ver URL, concatena el parámetro "rango" sin más)
  • en la web, sale todo ordenado por lastModified, por tanto una correción o modificación del evento hace que suba el evento arriba. No tiene mucho sentido. Yo si tuviera permisos de acceso para crear eventos, lo haría continuamente para promocionar mi evento al primero de la lista en mi categoría.
    La idea es priorizar las novedades y uno de los motivos para no dar permisos de modificación a los reutilizadores es evitar este tipo de modificaciones, si se quisiera tener permiso para modificar una actividad sería en un escenario de confianza en el que se haga un buen uso del api.
  • SOLUCIONADO Tras entrar a la sección "Fiestas Locales", aparece una nueva sección: JUVENIL
  • SOLUCIONADO Cambiar el título de http://www.zaragoza.es/docs-api/ (Swagger UI) a algo más atractivo
  • SOLUCIONADO En https://www.zaragoza.es/ciudad/risp/index_Api el literal "comporta sus datos" (en vez de Comparta)
  • SOLUCIONADO La web carga scripts no seguros, según Chrome (ver https://www.zaragoza.es/ciudad/risp/buscar_Aplicacion)
  • SOLUCIONADO la x y la y de lugar no están en wgs84, están en utm30 (pese a pedir wgs84)

API SOLR

  • SOLR devuelve ID con acto-id, y en el API REST eso corresponde a id (sin acto)Publicamos datos en SOLR antes que en API o SPARQL y optamos por ese formato para identificar los contenidos
  • fechaInicio_dt (pidiendo día 07, sale 06, por ser GMT): "2015-03-06T23:00:00Z", (es GMT)hemos añadido en https://www.zaragoza.es/ciudad/risp/camposindizados.htm la descripción para las fechas
  • documentar que hay que pasar "rows" para que devuelva el total del numCount en vez de un rows=10 que devuelve por defectoestá descrito (igual no muy visible) en https://www.zaragoza.es/ciudad/risp/camposindizados.htm
  • descripcion_t suele contener la información de lugar_t, pero no siempre (homogeneizar tanto en solr como con las otras apis)En SOLR hemos indizado en base a nuestras necesidades como web, si necesitais la información más desglosada se puede añadir al índice
  • El tema de las consultas FIQL es interesante pero el RFC no pasó a estándar y está obsoleto en 2008. Siete años depués... ¿igual es el momento de buscar alternativas mejores? :-DFIQL permite hacer consultas sencillas sobre los datasets pero seguro que existen mejores soluciones, ¿conocéis alguna?

API REST

API SPARQL

  • ¿se puede hacer que devuelva los objetos como el API SOLR en cuanto a no tener que acceder a "title.value"? (y englobado las dos apis en el mismo objeto, sea "bindings" -sparql- o "docs" -solr). Es decir, dar coherencia a las dos APIs para que devuelvan exactamente la misma estructura JSON.Son tecnologías diferentes y cada una tiene sus peculiaridades, el tema es que en SPARQL en la respuesta además del valor se obtiene su tipo de dato.
  • listado de los prefijos (PREFIX) cargados por defecto, no está documentado Lo hemos añadido en https://www.zaragoza.es/ciudad/risp/ayuda.htm

Común a todas las APIs

  • se devuelve contenido formateado en HTML en muchos campos. Es "de mala educación" ;-) y además no hay nada que identifique qué campo va a devolver texto o HTML, lo cual es peor todavía.
    Para que las APIs sean útiles para los reutilizadores, tienen que ser coherentes entre ellas (compartir todos los nombres de parámetros que devuelven, por ejemplo, y su contenido obviamente)Estamos de acuerdo, la justificación es que cuando nos planteamos publicar un conjunto de datos, publicamos lo que tenemos almacenado en la base de datos, si como reutilizadores necesitais la información más detallada nos podéis decir qué necesitáis y si es posible lo solucionaremos.
  • No puede haber peticiones sin documentar (lista de temas/subtemas en el API Rest, por ejemplo). Si todas las APIs funcionaran "como uno espera", esto sería menos grave... pero el hecho de que han ido evolucionando a ritmos diferentes, cubriendo necesidades diferentes, y el hecho de enfocarse a cubrir la necesidad de una web de dos décadas, aún se nota a la hora de usarlas. Por eso destaco el, al menos, que haya coherencia entre ellas y que estén bien documentadas. Van por buen camino, pero tal cual están ahora hay casos en los que no se diferencia mucho de "minar datos a mano", porque el reutilizador tiene que ir descifrando el funcionamiento del API.Ofrecemos diferentes formas de consumir la información, tanto SOLR como API como SPARQL son tecnologías diferentes con sus peculiaridades, en este punto estamos intentando mejorar la documentación y vuestras aportaciones son muy valiosas.
  • Con el tema de cambiar APIs y por tanto "joder" a reutilizadores que ya las estén usando... quizás haya que empezar a implementar VERSIONADO de APIs... Aquí por ejemplo hay un articulillo, aunque ya viejo (2011) de Mark Nottingham, miembro del W3C (el que redactó el RFC del lenguaje de consultas FIQL que usáis en el API SOLR) https://www.mnot.net/blog/2011/10/25/web_api_versioning_smackdown O por ejemplo, cómo documenta Github los cambios de su API https://developer.github.com/v3/versions/ Muchas gracias por la aportación, la tenemos en cuenta

@gimenete estamos de acuerdo en lo que comentas, lo entendemos como un comentario genérico sobre cómo deberíamos publicar los conjuntos de datos. Si por el contrario estáis pensando en hacer algún desarrollo sobre el dataset de actividades y necesitáis la información en el formato que planteas, estamos dispuestos a analizar lo que tenéis en mente para dar una solución adecuada. El tema es que hacer lo que propones implica cambios importantes y los podríamos asumir si existe un objetivo claro de reutilización.

Creemos haber contestado a todas las cuestiones, pero si queréis informarnos de errores o añadir más comentarios podéis crear issues en el repositorio https://github.com/zaragoza-sedeelectronica/zaragoza-sedeelectronica.github.io

@jrub
Copy link
Author

jrub commented Mar 26, 2015

Muchas gracias por tomar el tiempo en leerlo y arreglar esas pequeñas cosas 👍

Quiero contestar, así sobre la marcha a:
El tema es que hacer lo que propones implica cambios importantes y los podríamos asumir si existe un objetivo claro de reutilización.

Hay un objetivo claro para todos: la reutilización. Sin datos estructurados en las respuestas del API, se dificulta la reutilización. Hablo de los contenidos, no de la semántica. Lo que esta claro es que destacáis en semántica. Y lo que está claro es que lo que piden los reutilizadores son estructurar los contenidos.

Es un esfuerzo grande, pero personalmente estudiaría la posibilidad de hacer una versión 2 del API REST para empezar, unido a una versión 2 del Backoffice de introducción de datos, de manera que los que introduzcan los datos sólamente sean capaces de hacerlo "seleccionando de desplegables" para campos como precio, fecha(s), horario(s), lugar(es)... Obviamente descripción, título y otros sí serían textos libres.

Incluso propondría una mesa redonda entre "liberadores" y "reutilizadores" para definir las necesidades y lo que se puede realizar... todo esto lo estoy diciendo sobre la marcha., pero es que aunque se agradece un montón, y es un paso enorme el hecho de que os ofrezcáis a adaptar partes de APIs si hace falta, no creo que sea la solución a largo plazo... 😥

Al fin y al cabo, el esfuerzo necesario para no devolver texto libre donde no debería haberlo, es mucho menor que todo lo que os habéis currado de web semántica, ¿no? No sé, igual no estoy viendo el "full-picture"... pero creo que hay casos que no podemos resolver con las APIs actuales, por los motivos que comentamos de no estructurar las respuestas, por ejemplo, ¿podemos pedir que se devuelvan los eventos gratuitos con las APIs actuales? Teniendo en cuenta que el campo price a veces devuelve "Entrada gratuita", a veces "gratis", o incluso que el que da de alta los datos puede tener un error al escribir un texto libre y poner "grtis"... Sin embargo un { price: 0 } no da lugar a error. Y además, de nuevo, está el tema del i18n...

¿Os parece una locura lo de trabajar en una versión 2 de alguno de los APIs para empezar, de forma conjunta entre "liberadores" y "reutilizadores"? Esta claro que todos vamos pilladísimos de tiempo (y estoy hablando yo por mi mismo sin consultar a nadie...), pero yo al menos intentaría ayudar todo lo que estuviera en mi mano. Creo que es más productivo hacer UN esfuerzo en estructurar un API como decimos, a que 20 reutilizadores hagan 20 esfuerzos para tener que poner reglas del tipo "si pone gratis o pone gratuito o pone De Pago o pone veinte euros...".

Gracias de nuevo, un saludo a todos 😉
Javi

@gimenete
Copy link

Lo que comento en efecto es un comentario general, no por una necesidad particular. No estoy pensando en ninguna app en concreto. Hablo en general de cómo deberían servirse los datos.

Una idea: probablemente el cómo devolvéis los datos depende de cómo los introducís en las bases de datos. Para el ejemplo que he puesto de precios el usuario que introduce los datos no puede tener un campo de texto libre, tendría que tener un formulario donde pueda introducir las diferentes tarifas, por ejemplo.

Sobre el versionado de APIs, es una cosa a tener en cuenta, pero si lo que se hace es añadir campos a la respuesta, no se rompe la compatibilidad hacia atrás. Si hay un campo precio no pasa nada por mantenerlo y añadir un campo tarifas (por ejemplo) con los datos estructurados y que precio continúe siendo un campo de texto libre.

Otra cosa, además de que la información esté bien estructurada hoy en día las apps tienen que ser también atractivas. Idea: más contenidos multimedia en diferentes tamaños y resoluciones. Por ejemplo a la hora de devolver imágenes en vez de "image": ..../.jpg" propondría:

"images": {
  "hd": { "width": ..., "height": ...., "url": "..." },
  "big": { "width": ..., "height": ...., "url": "..." },
  "regular": { "width": ..., "height": ...., "url": "..." },
  "small": { "width": ..., "height": ...., "url": "..." },
  "landscape": { "width": ..., "height": ...., "url": "..." },
  "thumbnail": { "width": ..., "height": ...., "url": "..." },
}

Esto me permite elegir la mejor imagen para mi app y hacerla más vistosa. He puesto además de los tamaños en píxeles y sus urls un nombre a cada imagen porque esto me permite elegir el tamaño fácilmente. Y si quiero hilar muy fino puedo atender al width y height ignorando el nombre. Pero vamos, son ejemplos. Una imagen en landscape sería ideal para una cabecera de una web por ejemplo. Un thumbnail debería ser cuadrado y sería ideal para un listado, etc. Esto que puede parecer complicado es relativamente fácil de hacer con unos comandos usando graphicsmagick sobre la misma imagen y no añade mucho trabajo para vosotros si tenéis alguna imagen grande original y luego se escala en diferentes tamaños. Y sin embargo para un "reutilizador" esto puede ser un salto cualitativo importante.

Saludos,

@virtor
Copy link

virtor commented Mar 27, 2015

Aunque los comentarios sean en general, podemos abordar de forma conjunta el dataset de Agenda de Actividades, para lo que hemos creado un milestone sobre él. en https://github.com/zaragoza-sedeelectronica/zaragoza-sedeelectronica.github.io/milestones/%5BDataset%5D%20Agenda%20de%20Actividades

En él hemos creado las peticiones que comentáis, os pediríamos que añadierais comentarios a las issues que hemos creado (o que crearais nuevas) indicando el formato de respuesta que os gustaría obtener, aunque sea lo mismo que habéis indicado en este hilo.

Por otro lado hemos creado el milestone para Ayudas y Subvenciones (https://github.com/zaragoza-sedeelectronica/zaragoza-sedeelectronica.github.io/milestones/Ayudas%20y%20Subvenciones) ya que es un dataset que vamos a trabajar y nos gustaría nos dierais feedback de cómo debería ser la respuesta, o que nos plantearais "Historias de Usuario" a las que debería dar respuesta el dataset.

Saludos y muchas gracias por vuestro tiempo.

@txtbits
Copy link

txtbits commented Apr 8, 2015

Hola, soy Christian del equipo de desarrollo de la web municipal.

Hemos tenido en cuenta vuestras aportaciones, y tras ver que en otros sitios (Foursquare API, Google Places API, etc.) utilizan diferentes sistemas, similares entre ellos, pero sin llegar a ser un estándar para la publicación de estos datos, hemos planteado la siguiente solución:

Respecto a los horarios, nos sería más fácil implementar lo siguiente:

{
    "openingHours": {
        "periods": [
            {
                "day": "Monday",
                "open": "09:00",
                "close": "15:00"
            },
            {
                "day": "Monday",
                "open": "17:00",
                "close": "19:00"
            },
            {
                "day": "Tuesday",
                "open": "10:00",
                "close": "21:00"
            }
        ]
    }
}

Y sobre los horarios:

{
    "price": [
        {
            "hasCurrencyValue": 3,
            "hasCurrency": "EUR",
            "fareGroup": "regular",
            "minSize": "1"
        },
        {
            "hasCurrencyValue": 0,
            "hasCurrency": "EUR",
            "fareGroup": "zaragoza-card",
            "minSize": "1"
        },
        {
            "hasCurrencyValue": 5,
            "hasCurrency": "EUR",
            "fareGroup": "group",
            "minSize": "10"
        }
    ]
}

La idea es empezar por Agenda Zaragoza y extenderlo posteriormente a otros conjuntos de datos para normalizar estos campos.

Agradeceros vuestras aportaciones y tiempo para mejorar la publicación de los conjuntos de datos.
Saludos.

@jrub
Copy link
Author

jrub commented Apr 8, 2015

¡Gracias a vosotros!

Continúo la conversación concreta sobre los cambios del API de Agenda para precio y horarios a sus respectivos issues, para no saturar este hilo.

@jrub
Copy link
Author

jrub commented Apr 8, 2015

Un tema que no tengo solucionado para http://laAgendica.com es esto (copio de arriba):

@jrubr: descripcion_t suele contener la información de lugar_t, pero no siempre (homogeneizar tanto en solr como con las otras apis)

@virtor: En SOLR hemos indizado en base a nuestras necesidades como web, si necesitais la información más desglosada se puede añadir al índice

Para algunos eventos la gente se nos ha quejado de que no salen los horarios, o dónde es (esto último podríamos sacarlo del param lugar, pero como puede haber varios subEvents y tal, de primeras no nos complicamos metiendo eso y optamos por mostrar description_t, que suele llevar la descripción y el lugar y horario... pero no lleva estos últimos siempre)

¿Se puede homogeneizar esto de alguna forma, aunque sea a partir de eventos futuros y no aplique a los ya creados?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment