Notre expérience dans la création d'une API Gateway

Certain companies, including our client, develop their product through a partner network. For example, large online stores are integrated with the delivery service—you order a product and soon receive a tracking number for the package. Another example is purchasing insurance or a ticket for the airport express along with your airline ticket.

To achieve this, a single API needs to be provided to partners through the API Gateway. This is the task we solved. In this article, we will discuss the details.

Given: an ecosystem and an API portal with an interface where users are registered, receive information, etc. We need to create a user-friendly and reliable API Gateway. In the process, we needed to ensure

  • registration,
  • API connection monitoring,
  • monitoring how users use the end system,
  • tracking business metrics.

Notre expérience dans la création d'une API Gateway

In this article, we will share our experience in creating an API Gateway, during which we addressed the following tasks:

  • user authentication,
  • user authorization,
  • modification of the original request,
  • request proxying,
  • response post-processing.


There are two types of API management:

1. Standard, which works as follows. Before connecting, the user tests the capabilities, then pays and integrates it into their website. It is most often used in small and medium-sized businesses.

2. Large B2B API Management, where the company first makes a business decision to connect, becomes a partner with contractual obligations, and only then connects to the API. After settling all formalities, the company receives test access, undergoes testing, and goes live. But this is not possible without a management decision to connect.

Notre expérience dans la création d'une API Gateway

Our solution

In this part, we will discuss the creation of the API Gateway.

The end users of the created API gateway are our client's partners. We already have the necessary contracts stored for each of them. We will only need to expand the functionality, noting the provided access to the gateway. Accordingly, a controlled process for connection and management is required.

Certainly, it would have been possible to take some ready-made solution for API Management and creating an API Gateway in particular. For example, this could be Azure API Management. Cela ne nous convenait pas, car dans notre cas, nous avions dĂ©jĂ  un portail API et un Ă©cosystĂšme Ă©norme construit autour. Tous les utilisateurs Ă©taient dĂ©jĂ  enregistrĂ©s et savaient oĂč et comment obtenir les informations nĂ©cessaires. Les interfaces nĂ©cessaires existaient dĂ©jĂ  dans le portail API, nous avions seulement besoin d'une API Gateway. C'est prĂ©cisĂ©ment son dĂ©veloppement qui nous a occupĂ©s.

Ce que nous appelons API Gateway est une sorte de proxy. Ici, nous avions Ă  nouveau le choix - soit Ă©crire notre propre proxy, soit choisir quelque chose de dĂ©jĂ  prĂȘt. Dans ce cas, nous avons optĂ© pour la seconde option et choisi la combinaison nginx+Lua. Pourquoi ? Nous avions besoin d'un logiciel fiable et Ă©prouvĂ©, soutenant l'Ă©volutivitĂ©. Nous ne voulions pas avoir Ă  vĂ©rifier Ă  la fois la logique mĂ©tier et le bon fonctionnement du proxy aprĂšs la mise en Ɠuvre.

Tout serveur web a une chaĂźne de traitement des requĂȘtes. Dans le cas de nginx, cela se prĂ©sente comme suit :

Notre expérience dans la création d'une API Gateway

(schéma de GitHub Lua Nginx)

Notre objectif Ă©tait de s'intĂ©grer dans cette chaĂźne au moment oĂč nous pouvons modifier la requĂȘte initiale.

Nous souhaitons crĂ©er un proxy transparent, afin que la requĂȘte reste fonctionnellement telle qu'elle est arrivĂ©e. Nous contrĂŽlons simplement l'accĂšs Ă  l'API finale, aidant la requĂȘte Ă  y parvenir. Dans le cas oĂč la requĂȘte Ă©tait incorrecte, c'est l'API finale qui doit afficher l'erreur, et non nous. La seule raison pour laquelle nous pouvons rejeter une requĂȘte est l'absence d'accĂšs pour le client.

Il existe déjà pour nginx extension sur Lua. Lua est un langage de script, trÚs léger et facile à apprendre. Nous avons donc réalisé la logique nécessaire à l'aide de Lua.

La configuration de nginx (analogie de l'application route), oĂč tout le travail s'effectue, est assez comprĂ©hensible. La derniĂšre directive est particuliĂšrement remarquable - post_action.

location /middleware {
      more_clear_input_headers Accept-Encoding;
      lua_need_request_body on;
      rewrite_by_lua_file 'middleware/rewrite.lua';
      access_by_lua_file 'middleware/access.lua';
      proxy_pass https://someurl.com;
      body_filter_by_lua_file 'middleware/body_filter.lua';
      post_action /process_session;
}

Voyons ce qui se passe dans cette configuration :
more_clear_input_headers — nettoie la valeur des en-tĂȘtes spĂ©cifiĂ©s aprĂšs la directive.
lua_need_request_body — dĂ©termine si le corps de la requĂȘte initiale doit ĂȘtre lu avant d'exĂ©cuter les directives rewrite/access/access_by_lua ou non. Par dĂ©faut, nginx ne lit pas le corps de la requĂȘte du client, et si vous devez y accĂ©der, cette directive doit ĂȘtre dĂ©finie sur on.
rewrite_by_lua_file — chemin vers le script oĂč la logique pour modifier la requĂȘte est dĂ©crite
access_by_lua_file — chemin vers le script oĂč la logique vĂ©rifiant l'accĂšs Ă  la ressource est dĂ©crite.
proxy_pass — url Ă  laquelle la requĂȘte sera proxyfiĂ©e.
body_filter_by_lua_file — chemin vers le script oĂč la logique pour filtrer la requĂȘte avant le retour au client est dĂ©crite.
Et enfin, post_action — directive non documentĂ©e qui permet d'effectuer d'autres actions aprĂšs que la rĂ©ponse ait Ă©tĂ© envoyĂ©e au client.

Nous allons maintenant expliquer dans l'ordre comment nous avons résolu nos problÚmes.

Autorisation/authentification et modification de la requĂȘte

Autorisation

Nous avons construit l'autorisation et l'authentification en utilisant l'accÚs par certificat. Il y a un certificat racine. Un certificat personnel est généré pour chaque nouveau client du client, avec lequel il peut accéder à l'API. Ce certificat est configuré dans la section server des paramÚtres nginx.

ssl on;
ssl_certificate /usr/local/openresty/nginx/ssl/cert.pem;
ssl_certificate_key /usr/local/openresty/nginx/ssl/cert.pem;
ssl_client_certificate /usr/local/openresty/nginx/ssl/ca.crt;
ssl_verify_client on;

Modification

Il peut ĂȘtre lĂ©gitime de se demander que faire avec un client certifiĂ© si soudainement nous voulons le dĂ©connecter du systĂšme ? Ne faut-il pas réémettre des certificats pour tous les autres clients ?

Ainsi, nous avons progressivement abordĂ© la prochaine tĂąche — la modification de la requĂȘte d'origine. La requĂȘte d'origine du client n'est pas valable pour le systĂšme final. L'une des tĂąches consiste Ă  ajouter les parties manquantes Ă  la requĂȘte pour la rendre valide. Le hic, c'est que les donnĂ©es manquantes varient pour chaque client. Nous savons que le client vient Ă  nous avec un certificat dont nous pouvons prendre l'empreinte et extraire les donnĂ©es nĂ©cessaires du client Ă  partir de la base.

Si à un moment donné il devient nécessaire de déconnecter un client de notre service, ses données disparaßtront de la base et il ne pourra rien faire.

Gestion des données du client

Nous devions assurer une haute disponibilité de la solution, en particulier pour la maniÚre dont nous obtenons les données du client. La difficulté réside dans le fait que la source primaire de ces données est un service tiers qui ne garantit pas un fonctionnement ininterrompu et une vitesse de fonctionnement suffisamment élevée.

C'est pourquoi nous devions assurer une haute disponibilité des données clients. Comme outil, nous avons choisi Hazelcast, qui nous fournit :

  • un accĂšs rapide aux donnĂ©es,
  • la possibilitĂ© d'organiser un cluster de plusieurs nƓuds avec des donnĂ©es rĂ©pliquĂ©es sur diffĂ©rents nƓuds.

Nous avons suivi la stratégie la plus simple pour livrer les données en cache :

Notre expérience dans la création d'une API Gateway

Le travail avec le systÚme final se fait dans le cadre de sessions et il y a une limite sur le nombre maximal. Si le client n'a pas fermé la session, c'est à nous de le faire.

Les données sur la session ouverte proviennent du systÚme final et sont initialement traitées du cÎté de Lua. Nous avons décidé d'utiliser Hazelcast pour sauvegarder ces données à l'aide d'un job écrit en .NET. Ensuite, à intervalles réguliers, nous vérifions la validité des sessions ouvertes et fermons celles qui ont expiré.

AccĂšs Ă  Hazelcast Ă  la fois depuis Lua et depuis .NET

Il n'y a pas de clients Lua pour travailler avec Hazelcast, mais Hazelcast propose une API REST que nous avons décidé d'utiliser. Pour .NET, il existe client, par lequel nous avions prévu d'accéder aux données Hazelcast cÎté .NET. Mais ce ne fut pas si simple.

Notre expérience dans la création d'une API Gateway

Lors de la sauvegarde des données via REST et de l'extraction à l'aide du client .NET, différents sérialiseurs/désérialiseurs sont utilisés. Il est donc impossible de mettre des données via REST et de les extraire avec le client .NET, et vice versa.

S'il y a des intéressés, nous en parlerons plus en détail dans un article séparé. Spoiler - sur le schéma.

Notre expérience dans la création d'une API Gateway

Journalisation et surveillance

Notre standard d'entreprise pour la journalisation via .NET est Serilog, tous les journaux finissent par ĂȘtre envoyĂ©s dans Elasticsearch, et nous analysons les donnĂ©es via Kibana. Nous voulions faire Ă  peu prĂšs la mĂȘme chose dans ce cas. Cependant, le seul client pour travailler avec Elastic en Lua que nous avons trouvĂ© a Ă©chouĂ© lors du premier require. Nous avons donc utilisĂ© Fluentd.

Fluentd est une solution open source pour fournir une couche unique de journalisation d'application. Elle permet de collecter des journaux provenant de différents niveaux de l'application, puis de les transmettre à une source unique.

API Gateway fonctionne dans K8S, nous avons donc dĂ©cidĂ© d'ajouter un conteneur avec Fluentd dans le mĂȘme pod pour Ă©crire les journaux dans le port tcp ouvert dĂ©jĂ  existant de Fluentd.

Nous avons Ă©galement Ă©tudiĂ© le comportement de Fluentd en cas de perte de connexion avec Elasticsearch. Pendant deux jours, des requĂȘtes ont continuĂ© Ă  arriver dans la passerelle, des journaux Ă©taient envoyĂ©s Ă  Fluentd, mais l'IP d'Elastic avait Ă©tĂ© bloquĂ©e. AprĂšs la restauration de la connexion, Fluentd a rĂ©ussi Ă  transfĂ©rer tous les journaux vers Elastic.

Conclusion

L'approche choisie pour la mise en Ɠuvre nous a permis de livrer un produit fonctionnel en production en seulement 2,5 mois.

Si jamais vous ĂȘtes amenĂ© Ă  travailler sur ce type de tĂąches, nous vous conseillons de bien comprendre d'abord quel problĂšme vous rĂ©solvez et quelles ressources vous avez dĂ©jĂ  Ă  disposition. Soyez attentif aux complexitĂ©s d'intĂ©gration avec les systĂšmes de gestion API existants.

Comprenez ce que vous allez dĂ©velopper — uniquement la logique mĂ©tier du traitement des requĂȘtes ou, comme cela a pu ĂȘtre le cas pour nous, le proxy dans son intĂ©gralitĂ©. N'oubliez pas que tout ce que vous rĂ©aliserez par vous-mĂȘme devra ensuite ĂȘtre rigoureusement testĂ©.

Source : habr.com

Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS đŸ”„ Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster