API Gateway with YARP (Microservices with .NET 6.0) - FeedR episode #3

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hi it's peter from dogmentors and welcome to the third episode of building our simple microservices-based app called the feeder within this episode what we are going to talk about is the api gateway and there might be a variety of reasons why would like to actually add some kind of a gateway or maybe just a plain simple reverse proxy into your solution so let's say one of the core benefits and one of them let's say main reasons why you would like to have a gateway within your microservices based up like we have here within our solution is that especially i mean essentially what you would like to provide is some kind of a public facade on top of your system so when you think about the consumers of your let's say microservices you don't really want them to beware let's say that you have 10 or 1000 or 500 of different microservices you don't want them to be aware where these microservices live what are their ip addresses dnss how should they authenticate with to these microservices what transportation layer should they use and so on and so on so this is one of the core reasons why you might want to have the gateway in the first place so expose for example this single endpoint and of course you might think of for example having multiple different gateways let's say one gateway for the web apps one gateway with different endpoints different data for the mobile apps another one from desktop apps but in our example let's just focus on a single gateway so we'll have a single entry point and this will be responsible for at first properly routing the consumer of our microservices based solution to the actual services so that the end consumer of our api will not care what are the services how many of services are there which share which which instance of the particular service will for example handle this request what transportation layer is being used internally all right so for example our public api consumer might talk to us for the http but internal internally this might be for example using some websockets signalr grpc or anything else the same would apply for example for the authentication authorization maybe you like to add some request headers maybe some correlation ids or headers sent by the gateway to the microservices so there is let's say multiple reasons not to mention things like load balancing session affinity and many many others so today within this episode we are going to talk about the gateway and actually we are going to implement the gateway and to add gateway into our origin solution we are going to use a very nice library built by the microsoft which is let's say the official microsoft reverse proxy that you can find publicly on github and the arp as an acronym stands for yet another reverse proxy also in the past i did use in at least a few projects the oscillo gateway which i think is still probably the most popular api gateway written in net but i'm not really certain at least at the time recording this video what is the status of this project so i can't recommend it whether you should use oslo or not even though i really like this project also in the past just to let's say get a better understanding of how the gateways are being built i also built my own gateway called entrada so you can check out this code and just to see how you can also think of building your own gateway how this reverse proxy mechanism works and how you can apply some additional extensions to it but in this episode we are going to take a look at the yarp which by default is well stands for a simple reverse proxy but it's really nice and mature library that happy news at least what the some of the articles are telling us within internal within the microsoft some of some of them teams some of their divisions and they just decided to make it public which is actually great because on top of this very well established very fast reverse proxy you can build your own proper api gateway and since this is the well actually just an asp.net core middleware quite advanced but still asp.net core extension supported this in this words you can do pretty much anything with it and there is like lots of built-in features into it as you can see in the docs there is application load balancing there is request transformation data aggregation lots lots lots of stuff even things like health checking grpc so a lot of stuff and when i first used this quite some time ago there are maybe like a few sections within this articles right page now there is like dozens of them so that's really cool and i can see that they really put a lot of effort to make it very good and usable reverse proxima and i've been using them for quite some time now and i'm also very happy to say and to hear from their side that they finally released the production ready version 1.0 quite recently so let's now jump into the code and let's see how we can make use of the yarp and some of its basic features let's see how we can use yarp right so if you just type something like yarp.net you will find this link that will redirect you to this official reverse proxy for the yarp this documentation website and under the articles you'll actually find a lot of nice sample articles with code that you can use to start working with the yarp so let's jump into our code and let's expand our gateway project and we are simply going to install this reverse proxy all right so here we are going to install this yarp reverse proxy this nougat package and then we are going to add very easily the yarp into our project so we can do something like builder and then services and then you will find here this extension called add reverse proxy and now we want to load the configuration from the file so by using load from config extension we are just going to take our configuration object from the builder instance and then let's say we'll keep our configuration under the section called yard all right so this is going to add the required yarp components to our ios container and register all the remaining all the required services and now here let's just call up and then map reverse proxy so we can actually provide him provider some specialized kind of endpoints and middleware to make the to allow the arp to route our router direct our request to the provided endpoints for example based on the configuration file now let's move into our upselling json and here what we want to do is to provide this erp section so let's start with the yarp as our section name and we want to start with the rouse definition so here let's just start adding the routes one by one so since our gateway is going to be the only public facade right our only let's see public api that should be used by the end user uh consumers of our system we are of course not going to expose the gateway within the gateway we'll just expose the aggregator the notifier service and the order for remaining fixed microservices so let's start for example with the aggregator service so here i'll just say something like i want to have the route under leaving another aggregator unit name as the key within this json object within the dictionary and then at first i will say this is going to some kind of a cluster id so the cluster will be actually responsible for containing the urls the destination so-called destinations of our services so i'm just going to call my cluster id just aggregator the same let's say as my key here it doesn't matter just to you know be consistent and come up with some appropriate convention when it comes to naming your uh for example yarp endpoints definitions and now what i'm going to do is something like so i want to have this match so the match if you take a look and for example within this er documentation and at the section like how you can actually make this routing within your services so here you will find this for example match and then you can just provide some kind of a path also including some additional uh wild cards like this for example catch all wild card so let's see so what i want to do is something like so when someone sends a request to our base way gateway url which is localhost 5000 for now and let's say provide this additional aggregator as within the endpoint within the public endpoint we want to route it for example to our aggregator microservice so here i'm just going to provide some kind of additional additional wildcard so whatever will be sent under the gateway slash aggregator and then pretty much any kind of additional endpoint or query string i just want to forward this further to our upgrader service so here i'm going to say i want to catch anything that is part of this endpoint or query string whatever there is and then let this is going to be our path so let me just do it like this so the path of this for this match will be this uh end point this kind of you know let's say query and then we want to provide here so-called transformation and the transform that you can see here so we can transform a lot of stuff for example you can provide here some custom http request header transformation or like in our case some kind of path transformation so what we want to do is to redirect this to our aggregator service but we want to only um pass further we only want to provide this catch-all endpoint query string whatever there is we only want to send this filter we don't want to call our aggregator with additional aggregator endpoint at the very beginning right because it wouldn't make sense so we want to use this path only to say this is this puff this is the part of the gateway pointing to the aggregator microservice and then to our regulator microservice we only want to provide which actually makes only sense which makes them which makes sense only this part only this part right so whatever the end point whatever the question is without adding additional to our part and to our path this operator part so let me just uh provide here according to the docs this transforms and then within this dictionary we are just going to provide this so-called uh as you can see here path transformation pattern so i'm going to put there the puff pattern puff pattern and then i'm going to provide here well that's the only part of my path that i'm interested interested in so i don't care about this one i'm only interested about this one so this is what i want to transform this is what i want to pass further into our service now let's jump down here and under our routes what we want to do we want to provide well as you can imagine uh we like to provide here this kind of cluster definition so where our micro service actually lives so here let's just declare the cluster section within this yard configuration still within the same section our board section of the arp config and then i'm just going to provide for our key the first key which is aggregator this is our cluster id with the key aggregator so this is going to be my first cluster and then i'm just going to provide the destination so here according to the documentation once again there will be my destination and i can let's say for example called destination one doesn't matter where i call it and then the address for my destination is going to be uh well the actual address of our upgraded microservice so for now our aggregator lives under this localhost 5010 port so this is going to be the url right so now let's try to run our gateway and let's see if this is going to work so if i do for example gateway run all right we should be able now that we should be able to see that the gateway of course works so let's see 5000 should redirect us to the gateway but if i try to do something like slash aggregator let's see what happens i'm getting 502 which makes sense because as you can see in the logs the gateway tries to forward redirect this request kind of to our 5010 right as you can see there is this proximity to and this service url but our regulator of course is not working yet it's currently offline so it makes sense so let's run our aggregator now and we should see that our gateway when we reach this aggregator endpoint once again so the service is running and now we can refresh it and the data the response is here right so whatever will be put there further let's say aggregator and let's say for example abc this is going to give us not found because now we as you can see in the logs we try to reach our aggregator and then abc endpoint and of course here we don't have any path like that declared but if i were for example to add this path here let's say if i were to extend my api of the upgrade or service with something like abc endpoints and let's say hello from abc now let's run this aggregator once again and of course this is going to work now because i have this one more endpoint here right so we have this let's say one to one routing redirecting proxy request from the gateway to our micro services so the very basic usage of the yarp just to expose only the end points only the paths that we want to by using some custom conventions for example for different services name or maybe different modules um different versioning and different kind of you know wildcard patterns so a lot of stuff that you can do related to path definition header routing header request headers and transformation and so on so for now let me just quickly add here the remaining services i'll just copy and paste them from the existing config file let's see how this is going to work with all services being available and now let's talk about another cool feature of the arp all right so this is like a whole conflict for our overall system so we just have here all the services in place the aggregator right notifier three remaining data fits with the unique name as the qf in the dictionary with the path pointing to different services with the same pattern transform and of course with the different set of cluster identifiers so now we could run our services we could run our all the services and the gateway so six ups in total and we can just you know one by one start hitting our endpoints just as declared here so let's take a look okay so it's all up and running and now i can do of course we can reach our gateway and there is the aggregator right the first endpoint there is the notifier there is our there are our feeds so let's say the newsfeed the quotes fit and finally the weather fit right so that's very cool we have now a single app which we could expose to our api consumer from the outside world and then we don't care the consumer doesn't care how many services are there but of course internal internally we might have a monolith modular model with a bunch of microservices the end consumer doesn't and shouldn't really care so that's really cool now before we move on keep in mind that of course we need to provide the appropriate docker settings for our gateway so here for our options json i'm just going to provide here a new docker.json because when we build our docker image for this gateway and we are using this docker environment variable here which will try to load this docker settings of course from the docker let's say compose perspective or container perspective if we will try to run this service internally for example by using this and already existing docker compose file within this internal docker feeder network we can really use localhost there right because this would be a bunch of distinct containers so they can talk to each other by using this aliases right this specific names so for example if we were now to jump back into our docker config so i can just simply do the following i'm just going to leave the routes right so i'm not going to override the routes they are fine but instead we can override the clusters so i'm just going to change this from the actual hard coded urls to something like the names of our services based on our docker compose file here so we have the aggregator we have the notifier for this guy and then we have the three remaining fits so there will be fits for the news this one and then there will be the quotes fit this one and finally the weather fit this one so now we have the proper upsetting json file for docker usage and this will make our yarp our reverse proxy our api gateway it will make it work within the docker containers docker network as well so now let's take a look at additional feature which is called the load balancing right and of course there is more to load balancing than just setting up the gateway because there's there are also let's say challenges like service registry service discovery some additional balancing algorithms you might want to use so there are let's say depending on what you are going to use within your production environment you might just stick to some hardcoded urls or maybe you might decide to go with kubernetes and then use their service abstraction or maybe you might want to use tools like console fabio traffic or other service registry discovery or load balancers to make it work but let's just take a look at how the arp could help us with the load balancing right so imagine the following scenario let's say that we are going to run our aggregator so i'm going to just navigate to our aggregator service here and i'm just going to run this service under three different instances right so i'll just run the first instance and then i'm going to run the next instance and i'm just going to provide there these urls so for example i want to run the second instance independently from the first instance of course so the first one runs at 5010 the second will run at 5011 and the third one instance of this aggregator service will run under 5012 so we have three let's say we scaled horizontally for our console on the local host we scaled up horizontally our aggregator microservice into three independent instances right so we can now reach 5010 11 and 12. but of course if we will try to hit our aggregator for the gateway so if we run the gateway now let me just run it maybe also for the console so we can see the locks a bit better let me just negate here and let's just run the gateway you will notice that the gateway gateway will keep on hitting the first instance all the time so if i if we now refresh it and let's take a look i'm just going to refresh hit this request multiple times but if we're taking look into the logs you can see it's always forwarding it's always approximate to the same 5010 which of course makes sense because we didn't really declare anywhere within the gateway that we want to use any kind of load balancing right so here within our gateway let's see we are just pointing to the same single instance of our service so what if we would like to point different instances so now let's do something simple i'm just going to provide here let's say destination 2 5011 and then destination free which is going to be 5000 12. all right so let me just run it okay and now let's see what happens so if we reach it multiple times let's take a look now it seems to be working so we have multiple instances and depending on some built-in algorithm for example once it's being sent here to the first instance then the second instance then to the third insert instance of our service so some load balancing is already in place and as you can see by default it will use this power of two as a default choice for load balancing algorithm but if you want to change it we can do this quite easily so for example we can change this to round robin so let's take a look i'm just going to put it there and let's see if this is going to work so let me start and now if we take a look let's just run it multiple times once again so maybe to visualize it a bit better what i'm going to do is to just return some kind of unique id so within our ugly service let's just do the following i'm going to do something like our id which is going to be the new goods right and then i'll just return it here within this hello world message so the id will be something like this okay so uh now let's run this instances once again so the first one does run and then the second one with the urls 5011 and then the third one with the same urls 5012 all right and then of course the gateway so let's take a look how the round robin is going to behave like and there is the first instance second third first instance second third so you can see it's running as expected we have a basic ground rubbing low balancing place and we are reaching three instances one by one the first one second third first one second third and so on and so on so quite easy stuff to achieve some basic load balancing with the yarp but of course there is much more than that because what we've just seen is pretty much just a tip of an iceberg so let me show you one additional feature that i really like about the yarp so i'm just going to remove this id let's jump back into our gateway project and now i can do something like the transformation so as you can see in the docs we can do some kind of internal transformations here so if you take a look for the transforms you can transform for example based on your configuration file but what if we would like to do some kind of a transform for example for our request headers which is more than just um you know adding some starting value for the request header like this right so what if i would like to maybe for example use some dynamic header with some dynamically generated value for example some kind of request identifier correlation id which might be especially helpful when we like to correlate some of our requests starting from the gateway and then coming through distant microservices within the synchronous or asynchronous communication so here what i will do is something like add transforms and then here let me just do the following so the transforms and then i'm going i'm going to call as you can see we have a bunch of extension methods for for example request header transforms request transforms response header transforms and so on so i'm just going to call this kind of flexible at request transform like this and then within this request transform let's just call this one a transform for the specific request i'm going to well as you can see a bunch of properties that i can actually transform my path my query and so on my my context i can access the context here because still the arp is running within our asp.net core so we can access hp context and you can do pretty much anything you want even including the request body so i'm just going to call this proxy request and then headers and let's say whenever i hit this i want to provide some custom header here so i'm just going to call this something like request id let's just once again generate our uh unique value for the specific request by calling goodinguit to string and then i'm going to call this ads and let's just provide here some custom header like for example x request id and let's see what is going to happen now and i'm just going to return this uh value task completed task because i'm not doing anything a synchronous here so i don't need to await anything so let's take a look um i'm going to run this gateway in debug mode now all right so let's run in debug all right so let's jump into our aggregator now and here let's say i'd like to somehow get this pull this request custom request header so let me just pass here the hp context all right so internally i'm just going to call something like for example uh response rate async and our error message right so it's still working it's still returning some data but internally i'm going to call i'm going to do something like a request id and then let me take my request object and then the headers and from headers i'm trying i'll try to use this x request id as the header name so let's put it there and let's see if we are going to see any data in here let me just actually write it into our response as well so let me run this upgrade to service also in debug modes okay and let's take a look uh all right so let me now jump into elevator and of course we need to actually remove our load balancer settings so since i'm running only single app now for the upgrade to service i have to remove my destinations from here so i don't care about them anymore so let me just remove them and yeah leave it like this so let's rerun our um gateway once again and let's see what is going to happen now so when we reached our later let's see at first per each unique request we are generating some kind of identifier we are adding this to the headers request headers object and then let's see there is the 21b and now we are hitting our upgrader and let's take a look we have this request id with the same value and we are sending the response back and if i make another request of course the transformation will happen once again with a distinct unique id and the same request header is being passed to this microservice so looks like a very simple stuff but actually as i already mentioned quite powerful right things like unique ids request creation transaction ids whatever you call them are actually very crucial part later on when it comes to things like centralized logging monitoring or tracing so that's it when it comes to the arp a lot of good stuff here that you can find and this this features this set of features is actually being extended over time so i remember uh quite some time ago over a year ago when i started using the arp in one of the very first versions there were maybe just a few articles there now there is like i know 20 articles so a lot of stock here so i really encourage you to check this out okay so that's it for the episode hopefully you enjoyed building your own your custom api gateway as much as i did as you can see this is really really simple when you think about adding such a gateway into your own solution given that for example you are going to use yarp and with oslo it was also very simple but i think with vr is even simpler you simply install package the official vr package you just call some extension method on top of your ioc container extensions load the configuration and with just some basic reverse proxy in mind you can have your api gateway file functioning and then you just add some additional configuration here and there and you might set up some low balancing request transformation and many many other great features so as usual thanks for watching and see you in the next episode
Info
Channel: DevMentors
Views: 6,933
Rating: undefined out of 5
Keywords: feedr, devmentors, dotnet, yarp, api, gateway, api gateway, csharp, aspnet core, programming
Id: jn0SFUennII
Channel Id: undefined
Length: 31min 44sec (1904 seconds)
Published: Mon Dec 27 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.