Spring Tips: Bootiful Edge Services

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi spring fans welcome to another installment of spring tips in this video we're going to look at different patterns to help you build better edge services to be able to talk to your downstream micro services and we're going to see three different approaches in the spring ecosystem reactive programming spring cloud gateway and spring graphql so let's go going first we'll introduce two back-end microservices to which we'll make connections one is the orders microservice and the other is the customer's microservice customers gives us access to customer data the id and the name and it has an in-memory database of of records there and it's exposed over http on port 880 there's an endpoint called customers from which you can get all the customer records no big deal there's an orders microservice which represents all the orders associated with a given customer and this runs in port 8181 using r socket so that's not http it's a different protocol and we're going to use these from our edge service let's go back to the initializer and we're going to build a brand new project using start.springleo i'll use the latest and greatest version of java we're going to call this the uh edge service we're going to use springboot 2.0 2.6.0 not because we want springboot 2.60 per se but because what we want access to the maven snapshot and milestone repositories and that will automatically configure it for us we're going to go ahead and add the reactive web support our socket support we're going to add redis support we're going to add security support i'm going to add spring cloud gateway all right now i'm happy with those selections let's hit generate and we'll open this up in our ide [Music] all right first things first let's go to palm.xml and set this back to 5.4 we're going to keep the configured repositories of course uh while we're here we'll bump this up to 17 because it's out now it's awesome and we want to add the graphql spring boot starter which we'll use later we want to comment out the spring security support right now spring security we don't need the spring security r socket support at all nor do we need this one we do need spring boot starter security for http however and we're going to comment that out as well all right so i think i'm happy with that let's go ahead and hit maven reload uh now let's build our code now so we're going to use spring cloud gateway spring cloud gateway is a generic api gateway it's a lightweight api gateway and there are a couple ways you can use it you can use it from property files from yaml or from the java api i'm all about that no yaml life but i can understand why you would want to use something like the ammo configuration for dsls like spring cloud gateway's dsl so let's take a look at what that looks like let's go to this file delete it i'm going to create a new file called application dot yaml okay so let's go to application.yemen we'll paste in an example of using spring cloud gateway we've got a a very simple route here sprinkled gateway is composed of zero to end routes that you define they can have logical names each round has a predicates that match incoming requests which are going to come into this gateway node running on port 99.99 uh it's going to match the requests that come in at four size proxy having a host header of wildcard dot spring that i o the double asterisks is the escape mechanism but it's actually just one asterisk uh we're gonna then process the incoming request by passing it through a series of filters of which these are just but a few and then we're gonna send it on to localhost 880 which again is where our http customer service lives so you can use this this is already kind of an interesting uh project right we can run this and see what we get already oh it looks like i've neglected to put the spring cloud version back to where it would be on 2.54 let's go back to the initializer explore copy and paste this go to palm.xml that re-import and restart okay so the application's up and running we can test it out by going to the command line and we can say the host header is hello.spring.io going to localhost 99.99 forward slash proxy and when we do that we get the json back from the customer service right so that's worked great um we can also express this configuration through uh you know properties i told you and and the benefit of yaml and properties is that you can store this configuration not inside the jar but externally in the spring cloud config server whose definitions can then be reloaded you can actually change things without restarting the config server uh the the configuration of course lives in git so it's versionable it's auditable it's you know it's great for that kind of stuff and you can actually force your spring cloud gateway code your your service to restart the configuration to refresh the configuration without restarting the jvm itself so that's really convenient now i like the property file approach or the ammo file approach for this but i also like the the java api and the way that looks is if you just create a a route locator instance so you say route locator builder and you build routes so build return and each route has a predicate four slash proxy for example and host.wildcard.spring.io and the route will be sent onward to something like like i said earlier it's going to be 8080 the customer's endpoint but the customer's endpoint is the path so i'll use the filter and the filter will be customers right so there we are there's my customer's endpoint and that's the same thing now i love spring cloud gateways filters right this is uh you can actually do really amazing things oh i think we've got to add the response header so let's do that http headers dot access control origin no big deal but there's other ones as well you can do a retry for example right you can say i want to retry like 10 times you can do you know all sorts of circuit breaking you can do lots of things one of my favorite is to use the rate limiter and the way that the rate limiter works is you configure an instance of type rate limiter which is a bean uh the default implementation will store data in um in redis right so rate limiter and redis is nice because it's an external data structure server uh and uh it um it'll keep track of requests into your service right and so you can actually uh keep that count external to the instance so if you deploy 10 instances of this gateway to your load bouncer they all share the same atomic number in redis and then so if you configure in this case i configured five requests per second bursting up to seven and if you if you exceed that you got like you know five instances of your your your gateway deployed across the load bouncer then each can get one request per second basically right they don't all get five it's not 25 it's just five across all of them which is what you want you want that budget to apply globally okay so i'm going to use the redis rate limiter here that's great uh redis of course is a key value server so you need to specify a key resolver uh the key resolver can be you know anything right like um right this is from la vita bella with roberto bernini that's fine uh you can also look at the incoming request and take the principle and then map the principle to the principal name and if the request doesn't have that you can just return an empty one and you know that's fine and that means that the authenticated user uh will get its own key so five requests per user which is fine and that boils down to a nice concise lambda or you could just use the one that we wrote which is nice that's very very concise or you could just not specify anything and you'd get the same behavior because that's actually the default so that works out very nice as well right but that does mean we need to have a principle somewhere who's installing their principle for us well obviously spring security is our friend here so we're going to bring spring security back in and spring security of course handles uh you know authentication and authorization so let's configure that here so we'll say bean map reactive user details authentication return new map and i'm just going to create a default user uh jlong and the password will be pw and the roles will be user and build okay so there's my default authentication and we're going to create a user as well security web filter chain authorization and here we're going to just configure how uh you know how we we limit access to certain endpoints right so let's create this we'll say authorized exchange a e a e dot path measures proxy needs to be authenticated otherwise we're going to say any exchange is going to be allowed to go through uh undisturbed basically now this is this is going to assume that they're authenticated how are they going to authenticate well they're going to use um http basic so i'm going to say go ahead and use that but we don't want to have csrf because that'll make our little demo a little bit more difficult by being more secure which is good but uh not great for my demo so okay we've got authorization and authentication let's see if this works all right so it's up and running this i'm going to make the same request as last time but it's going to fail this time right and the reason is because we're not authorized you can see it says 401 unauthorized so um we want to say minus u this is http basic for the username and password and there's our data it worked and we can see the rate limiters kicking in uh you know giving us how many rate limit capacity we have how much rate limited capacity we have left and we can we can even drive this you know while true do and then done and before i kick that off let's log into redis and do dump all or sorry flush all okay so if i do keys there's nothing there kick that off and now you can see there's a rate limiter that's being a key that's been used to persist the number of requests that have been made i control c that go back here refresh a few times and it clean itself up so the gateway is really great for this kind of stuff really turn key easy to use really advanced functionality now this is great for generic cross cutting kind of stuff like routing compression security authorization oidc jot whatever all that kind of stuff that you want to handle gateway probably can help you there that said one of the real major use cases for api uh edge services like this is uh adapting clients to services in visa versa right uh and netflix was a famous example of this uh they hadn't they as you know they have a number of different clients who can't think of a client on which they can run netflix right android ios ipads your tvs your playstations your rokus your xboxes everything right everything speaks netflix these days and they all have their own quirks their own protocols their own authentication their own you know payment scheme everything right so netflix maintains a bevy of different clients and of course this contributes to the testing burden considerably uh rather than having to adapt every single deployed microservice no matter how homogeneous uh to each client they they created a edge service that way that acts as an adapter it takes data from the services and adapts it to the particulars of the client that's accessing it this is great especially if there's weird defects or bugs or whatever it canonicalizes uh it allows the microservices to stay the same and to be pretty homogeneous if necessary while allowing different clients to talk to them even if they may not be compatible with services directly so let's create um an edge service that adapts our data rather than just acting on the payload or the envelope of the data as we do with sprint cloud gateway we're going to use reactive apis to talk to the downstream services right and remember the downstream services give us two things it gives us a record so customer integer id and a string name for customers and there's a record for orders integer id integer customer id okay and we want to use this crm client to talk to those i'm going to create a endpoint to talk to the downstream http service using http i'm going to use the reactive non-blocking http client to talk to our http customer service and i'll use the reactive non-blocking r socket requester to talk to our r socket okay so there we are there's our crm client let's now create some builds web client dot builder and our socket requester you can see that they look pretty similar right the difference of course is that our socket starts up it's it's stateful it's multiplex so when it starts up and it starts up and the application starts up and it stays connected for the life of the application you can configure to auto retry and all that but the point is it's the ideal scenario is that it stays connected that saves considerably on the constant network connection act handshake all that kind of stuff you just do it once per application okay so now we've got these bits here let's use them to create these clients of these downstream services okay so let's get the customers we'll use the http client uh http localhost 8080 forward slash customers i'm going to retrieve the data it's going to be turned into a reactive stream of customers et voila and for orders we want to get the orders so get orders for integer customer id and here we're going to say route this.rsocket.route dot cid where that's the customer id and we're gonna expect to get back a stream of orders ah not bad good stuff so now we have our our apis let's um let's combine them right this is the wheelhouse of uh of reactive programming is that you can combine different apis you can compose them in this case it doesn't matter that one is our socket and the other one is http because we're using reactive apis it doesn't matter whether we're talking to kafka or database or a rest api or socket or website or whatever at the end of the day you're just dealing with two types flux and mono both of which implement the reactive streams publisher interface so this is a kind of a de facto specification and everything stems from that so you can pass around references to publishers now i have uh i'm assuming i'm taking a good faith that this service will never go down but of course that can't be that's not going to always be true is it so nice thing about reactor or this library that implements these reactive stream specs is that there's good support for handling exceptions i can say you know let's return uh you know an empty stream if there's an error i can say i want to retry i want to retry 10 times or i want to retry uh with a back off attempting it 10 different times and you know waiting longer for each retry i can do timeouts of course i can say let's wait one second you know all sorts of things and these are reactor apis not web client or r socket or whatever these are not part of uh the protocols i'm speaking these are just part of being reactive and so i can do that for both calls and it's the same exact code right so that's very very powerful but now i want to build like i say a a composite i want to compose these streams of data so i'm going to create a new aggregate here customer orders and it'll be a customer on the left the first field is a customer and then a list of orders on the right all right so there's my my aggregate it's custom orders and i want to create a new endpoint that returns both the customers and the orders for those customers right so get custom orders return this dot customers dot flat map and what i want to do is given a customer this c customer given a customer i want to store both in memory and so i'm going to use a tuple a tuple's like an array where each element has a type and the element on the left is going to be a reactive stream for the customer and the element on the right will be the reactive stream representing the order so i'll say get orders for customer.id and i'm going to collect that stream of orders into a list so now i've got two reactive streams one on the left representing the customer and the one on the right representing the list of orders i can say give me t1 that's the customer give me t2 that's the orders let's create a new customer orders object tuple dot t1 tuple dot get t2 and voila right just like that i've made a call and again this is an n plus one thing i'm making a call to both services at the same time i'm calling the customers endpoint getting all the customers back but then for each customer that i have i'm getting all the orders but the nice thing is that i'm using reacted apis so it's not it's not doing this in a serial way it's doing it concurrently right it's very very powerful this way uh and so i'm not waiting any longer than the cost of calling the orders endpoint once basically now i've got my customer orders endpoint let's go ahead and create a controller a crm client rest controller to prove that that's working and i'm going to use my crm here okay and we'll just say inject return this dot crm dot get custom orders i'll go ahead and restart okay localhost cos voila it's worked there's our customer data and our order data each one of them nicely stacked you know together next to each other so i have access to both in my api the composition requires calling two different apis i'm in a much better posit the composition requires calling two apis i'm in a much better position to do that on the server side than the client would be you know especially android ios clients where they're going through tunnels and losing bandwidth and all that stuff imagine you your client calls the customer api uh and then has to call the other one well first of all that means that the client now needs to speak both http and our socket but second of all uh you know it also means that the client has to authenticate twice and third of all it also it means it has to get the data and do this orchestration on the client we can do all that centrally using this api gateway and the api adapter now i like this we've created a view of the data specific for a particular client and it wasn't that bad reactive making active programming makes doing the right thing concurrently as trivial as possible and obviously i'm using java which is nice and concise uh but you know if you're using kotlin this gets even more concise if you're using java it's even more concise so it wasn't a lot of code it wasn't hard to understand because we're using reactive apis so even though it's a simple thing it's also the most performant thing it's rare when you can have both uh but we do here right that said um you're gonna find you have to do this a lot right if you have different clients you're gonna end up creating different edge services for each client and um that's only for the moment right i mean any even the most sort of conservative of organization uh is going to have to create a browser-based html client uh a android client and an ios client that's just part and parcel doing business in today's world right uh at the very least um you know goodness knows what tomorrow holds but there's all sorts of unique opportunities and you want to be able to to meet those new opportunities but if part of that means adding a new api on the server side then things slow down don't they so what we want is to have the data that we want when we want it in the shape that we wanted and there's a bit of a tension here because we have different microservices each of which has data in its own shape and we want this shape to look like what the client wants so it's very tempting to just say well let's just put together a bunch of edge services to accommodate these clients and that's you know certainly an option that's what netflix did in the beginning that's part of the reason that they got so good at gateways right just why they created the zuul gateway and you know there's certainly some value in it but at some point i i imagine you just got to get tired of having to constantly adapt downstream services to be and look like one cohesive hole for the clients and again one of the reasons you do this one of the reasons you make a new endpoint that just composes these other endpoints is for practical reasons like latency like security right you want to have all the security in one place instead of having to duplicate it across different microservices um but again but eventually if you start doing this just because the data shape isn't right that i think would get old pretty quickly so this is a tension here one you want the data in one place you want it to look and feel like it's one cohesive hole on the other you don't want to give up the isolation and the ease of deployment and the evolutionary benefits that you get by using microservices and so this is the same problem that facebook experienced back in 2012 when they created graphql they open sourced that in 2015 and of course there's a graphql java project which is well maintained well liked and so on and so the spring team worked with the graphql java team to build the spring graphql project which is as yet experimental not yet ga but we can easily use it and it's building on a very rich robust layer of code so we'll use spring graphql which is ssa a milestone to integrate our types to integrate our apis here we have three concepts queries which are reads mutations which are updates and subscriptions which are sort of like queries that last a long time that could go on forever that could go on for indeterminate amount of time so you describe your types in terms of a schema which lives in our case in the graphql folder so we're going to create a new file here called schema.graphqls so we have a schema at the root of the schema is a is a type called query now this is a sort of well-known type that you have to create uh it's you know every project will have type query somewhere and queries or types rather have fields in this case we're gonna have a field to list all the customers a single customer would be significant thusly but multiple customers are wrapped in a bracket we can define the customer as well the customer has an id and a name and we want it to reference conceptually i want all the orders to be available there as well so i'll create another type called order uh and again before we we created it as sort of uh you know customers and orders are separate fields or separate endpoints that you could call we're going to create the type order give it an id field i'm going to give it a customer id field right and that's it customer order these are our two relationships or two types we could also have another field here called orders there's nothing stopping us i just think uh that realistically for for my first cut even though i've got two different micro services i'd like people to people to be able to get the customer data back with the orders data in there okay so let's do that now this is a query but again you could have two other types of data you could have subscriptions and mutations right and your queries can have parameters you can say orders by customer id right and then that would give you a list of orders right and that's a a query that takes a parameter called customer id but you're specifying all this upfront so it's very clear what's accepted what's expected what's returned etc and the same you know the the approach is basically the same for mutations you could have a update order order id id or whatever right name string and then this this would return a customer right and you could you could then update that um so let's go ahead and implement our query our query is going to live in a controller so at controller class crm graphql controller and we're going to create a query mapping which requires the spring graphql project so we'll go back to our build make sure it's re-imported okay and the query mapping is going to give us all of the customers okay and for now we'll just return empty uh we're going to inject our crm which has served us well all right so we'll say turn this.crm dot get customers great so that that'll work this query mapping annotation is a convention right it's a way of saying that we want to return a field called customers uh from the you know it's a it's a resolver this method this controller handler method is a resolver for the field called customers in the query type query mapping and if you look at this this is actually a specialization of schema mapping kind of like the relationship between git mapping and request mapping in spring mvc and spring web flex and actually we need to use schema mapping here for the orders data so we said that their customer data will come back from the customer's field well we said we want to get the orders for a given customer and in order to do that we need a reference to the root customer so spring graphql will give us a pointer to that and we're going to use that to resolve this.crm.getorders4customer.id and there we go so the field is called orders the type is called the customer and again we could you know this one here could have been it could have been this i could have been saying this and that's functionally exactly the same thing right so okay localhost graph iql we get this nice uh in you know shell that gets populated for you by the spring boot uh starter and by the way this is the same one that spacex uses right it's actually very popular very very familiar you can actually interrogate all the different queries from the spacex organization uh and all their subtypes and all that and so that's what we're doing here we have the same thing so we want to read the data and we want to ask for the customers well the customers are in turn composed of subfields id and name and orders so we need to specify we need to pull out which ones we want so here i want to get the id okay i also want to get the name all right i also want to get the orders right well the orders themselves are a complex object and they have subfields as well so we need to say we want id what else can we do we can get custom customer id great look at that so i got the id the name and the orders if i don't want the orders i don't pay the cost for them i don't have to make that call to the order service right behind the scenes you know that there are two different microservices here i'm fanning out the requests across different nodes getting the data concurrently right i'm not wasting time that bad huh you can ask for what you want you get what you want and nothing extra you don't have to waste time uh you know rebuilding the new api if you don't need it and the server isn't going to evaluate the orders calls it's not going to call the order service if you don't ask for the order data right very very powerful okay this is a this is one of the reasons that people love graphql because it's just it's as easy as this and when you use a graphql client you can connect over different protocols too we're using http but you can also use the websocket endpoint springboot has support for that as well in which case your javascript code would just talk to the graphql websocket endpoint which gets automatically created for you and you send queries you send literally multi-line queries like this uh you know multi-line multi-line strings that have this exact payload this this json not json this this schema this whatever this query type in there you just send that and it doesn't matter if you're asking for just the customer's data and there's only 10 customers you'll get that if you are going to call a subscription endpoint and you're going to have an ongoing uh stream of records then your your javascript code will just keep getting callbacks until you know you disconnect right or if you're doing a mutation it'll send the data to the server and and then give give give you the results and then you're done right so it's just very straightforward all right i hope you got something out of this i hope you learned something obviously we've only just begun to scratch the surface there's a lot of potential here i think you'll agree that's just waiting for you to take advantage of these are all small easy things you can do to build better api gateways and edge services and api adapters to help you connect your services to your clients which are after all the very last step between you and their customers right if you can get the clients right and get those into your customers hands they're happy that's the ball game everything is good after that so good luck enjoy your journey to production and as always we'll
Info
Channel: SpringDeveloper
Views: 7,977
Rating: 5 out of 5
Keywords: Web Development (Interest), spring, pivotal, Web Application (Industry) Web Application Framework (Software Genre), Java (Programming Language), Spring Framework, Software Developer (Project Role), Java (Software), Weblogic, IBM WebSphere Application Server (Software), IBM WebSphere (Software), WildFly (Software), JBoss (Venture Funded Company), cloud foundry, spring boot, spring cloud
Id: nrTw4w1xJck
Channel Id: undefined
Length: 30min 4sec (1804 seconds)
Published: Wed Sep 29 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.