Cómo escribir una API incorrecta

Escriba el código como si estuviera acompañado por un psicópata violento que sepa dónde vive.


Hola a todos!


Trabajo como líder del equipo de Desarrollo de Integración en el servicio de reserva de hoteles en línea Ostrovok.ru y hoy me gustaría compartir mi experiencia con varias API.



Como desarrollador de un sistema que trabaja con proveedores externos, a menudo me encuentro con varias API, la mayoría de las veces es SOAP / REST o algo similar a ellas. Sin embargo, trabajar con muchos de ellos deja la impresión de que fueron escritos, no guiados por reglas técnicas o sentido común, como si fuera del libro "Bad Advice" de Grigory Oster. En este artículo intentaré describir tales casos al estilo de "malos consejos" y considerar ejemplos relacionados con XML. Comentarios y discusión son bienvenidos.


Antecedentes historicos

SOAP (del inglés. Simple Object Access Protocol - un protocolo simple para acceder a objetos) - un protocolo para intercambiar mensajes estructurados en un entorno informático distribuido. SOAP fue originalmente diseñado principalmente para implementar llamadas a procedimiento remoto (RPC). Ahora el protocolo se usa para intercambiar mensajes arbitrarios en formato XML, y no solo para llamar a procedimientos.


Ir a los ejemplos


1. Pasar xml a url


¿Qué quieren más los usuarios de API? Por supuesto, simplicidad, fiabilidad y concisión. ¡Así que no leamos el cuerpo de la solicitud, sino aceptemos XML como información codificada en URL como un parámetro de la ruta de solicitud! Qué podría ser mejor:


http://exapmple.com/xml/form.jsp?RequestName%3DHotelRequest2%26XML%3D%3C%3Fxml%2Bversion%3D%221.0%22%2Bencoding%3D%22UTF-8%22%3F%3E%0A%3CHotelRequest2%2BBuyerId%3D%22test%22%2BUserId%3D%22test%22%2BPassword%3D%22test%22%2BLanguage%3D%22en%22%2BHotel%3D%22-100%22%2BProductCode%3D%221--%22%2BArrivalDate%3D%2223.12.2018%22%2BDepartureDate%3D%2224.12.2018%22%2BArrivalTime%3D%22%22%2BDepartureTime%3D%22%22%2BCurrency%3D%222%22%2BWhereToPay%3D%223%22%2BNumberOfGuests%3D%220%22%2BNumberOfExtraBedsAdult%3D%220%22%2BNumberOfExtraBedsChild%3D%220%22%2BNumberOfExtraBedsInfant%3D%220%22%2B%2F%3E 

Todo se vuelve simple, y no hay necesidad de restar un cuerpo de la consulta; nunca se sabe qué problemas puede haber con ella.


Spoiler

No sabré por qué se hizo esto. Los problemas aquí son los siguientes: muchos servidores tienen un límite en la longitud de la ruta de solicitud que puede atravesarlos. Si el XML es grande en volumen de datos, entonces puede causar el error 413 Entity Too Large como uno de los escenarios. Además, la cantidad de información está aumentando, ya que codificamos la URL antes de enviarla.


2. Transferencia de información a través del anidamiento excesivo de objetos de datos


Pensemos cómo hacer que la información en las respuestas sea lo más difícil posible. ¡Usemos estructuras anidadas, e incluso en diferentes formatos! Apenas dicho que hecho


 <Request> <InnerRequest> <RQ>[{"someInfo":"base64Data"}] </RQ> </InnerRequest> </Request> 

De hecho, el xml de nivel superior, dentro de él es otro xml, y dentro de él está json, en el que los datos se presentan en base64, y nuevamente json, ¡y ya contendrá la información que necesitamos! Una gran solución, casi como un cuento de hadas sobre la muerte de Koshchei, escondido en un huevo.


Spoiler

Uno de los inconvenientes más notables es la desaceleración en el análisis de la respuesta hasta que se pasan todas las estructuras anidadas, y luego puede resultar que el código de error esté conectado en json, en lugar de en niveles más altos. Entiendo que codificar datos binarios en base64 dentro de xml / json es una práctica común, pero codificar un formato diferente dentro de un formato diferente ya está más allá del bien y del mal.


3. Agregar información que no está relacionada con los datos de la solicitud y que no es válida dentro del formato de datos


Supongamos que XML nos llega en el cuerpo de la solicitud, lo procesamos y damos una respuesta. Parece demasiado complicado para un sistema bien diseñado y muy cargado. Obliguemos a los usuarios a enviar el tipo de datos en el cuerpo de la solicitud. Como hacer esto Justo en el cuerpo de la solicitud, por supuesto.


 XML= <Request> ... </Request> 

De una manera tan simple, siempre sabremos que recibimos una solicitud en formato XML.


Spoiler

Resulta que debemos agregar más bytes iniciales al cuerpo ya formado de la solicitud y solo después de eso será posible realizar una solicitud. Afortunado si no necesita cambiar los bytes iniciales según el tipo de datos de solicitud. En este caso, sería mejor usar el Encabezado http para indicar el tipo de datos y no cambiar el cuerpo de la solicitud.


4. Duplicación de datos sin necesidad


Supongamos que tenemos información muy, muy importante en la estructura de la respuesta XML. ¿Cómo mostrarle esto al usuario? Lo más obvio: demostrémoslo varias veces como parte de la respuesta, entonces definitivamente le prestará atención.


 <Response> <Obj Info="Important"> <ObjSetting Info="Important"/> <Name>SomeName</Name> <Info>Important</Info> </Obj> </Response> 

Después de eso, el usuario final definitivamente prestará atención al campo Información.


Spoiler

En este caso, lo pensé e incluso le pregunté a la compañía que proporcionó la API sobre el significado del campo Información y si la información en las etiquetas a diferentes niveles sería diferente. La respuesta fue: no, no lo hará, se duplican entre sí. ¿Por qué engañar a los usuarios y dificultar la respuesta si esto no es necesario?


5. Pasar parámetros del mismo tipo individualmente, no una matriz


En una de las API que utilizamos para buscar hoteles, hay campos que indican la edad de los huéspedes. ¿Qué formato de presentación se usa mejor para transmitir esta información? Deje que el formato sea así: cada edad será una etiqueta XML obligatoria separada, y consideraremos el valor 0 como la ausencia de este parámetro.


 <Request> <Age1>20</Age> <Age2>20</Age> <Age3>0</Age> <Age4>0</Age> </Request> 

Spoiler

Aquí hay varios problemas a la vez: no extensibilidad, información redundante, además, la edad realmente puede ser cero si los invitados son niños recién nacidos. En este caso, debe usar una matriz, en lugar de etiquetas con nombres únicos.


6. Reenviar información de solicitudes anteriores como parte de la cadena de llamadas API


Es hora de pensar en la seguridad de nuestra API. ¿Cómo entendemos que el usuario recibe información de nuestras respuestas anteriores? ¡Que nos envíe nuestra respuesta, por supuesto!


 <Request> <RequestInfo/> <PreviosResp> ... </PreviosResp> </Request> 

Spoiler

Para continuar trabajando con la API, es necesario enviar toda la respuesta del sistema externo desde los pasos anteriores de la API, y no algunos datos importantes de la misma, o incluso un hash que definitivamente corresponderá a esta respuesta. Exceso de datos en todo su esplendor.


7. No utilice marcadores de un error ocurrido, como una etiqueta de error o un código http


Hicimos nuestra hermosa API y la presentamos al mundo. Pero una vez que algo salió mal y no pudimos formular una respuesta al usuario debido a un error interno. ¿Qué hacer en este caso? Simplemente proporcione una plantilla de respuesta, sin datos, sin códigos de error o cualquier otra información. ¡Nadie debería saber que nuestra API ideal a veces puede no funcionar!
Un ejemplo de tal respuesta:


 <Response> <ImportantInfo/> </Response> 

- con un código de respuesta de 200 OK.


Spoiler

Acallar los errores cometidos es una muy mala práctica. El problema es que todo parece que no hay problemas en la respuesta: no hay una etiqueta <Error> , el estado de http dice que todo está en orden. En este caso, es necesario hacer una validación adicional de la información recibida para que no haya consecuencias imprevistas en nuestro sistema.


Conclusión
A pesar de la gran cantidad de documentación sobre el trabajo con tecnologías SOAP / XML y diseño de API, muchos problemas siguen siendo relevantes, y algunas soluciones son contrarias al sentido común. Espero que con este artículo pueda llamar la atención de los desarrolladores sobre los enfoques menos exitosos para reducir su número en el futuro.

Source: https://habr.com/ru/post/445346/


All Articles