 Hello developers. My name is Matt Rabel and I work for a company called Akta. Akta allows you to add authentication, authorization, and user management to your apps very quickly, very easily. You can find me on Twitter at M-Rabel. You can also find me on RabelDesigns.com that's my blog that I started way back in 2002. You can find me on LinkedIn under M-Rabel. And today's blog post that we'll be developing is basically Fullstack Reactive with Spring Web Flux, Web Sockets, and React. So I collaborated with Josh Long on this post and we wrote a few posts to proceed it. One being Getting Started with Reactive Programming in Spring and Building Reactive APIs with Spring Web Flux. And so what I'm going to do today is I'm going to go through the Building Reactive APIs part and then I'll go through this tutorial which actually uses React to build a real-time UI and talks to that backend API, gets its information displays it and updates it automatically. So let's get started. I have a demo here that I use and you can find as well. So you'll see it's on Akta Developer, Akta, Spring Web Flux React example is the name of the project and then there's this demo.adoc in the React app directory on the React app branch that I'm using to do this. So I'm going to be using a number of Intellj Live templates and these are basically shortcuts that I can use to just recall a bunch of code and I'll have to type it out very verbose so you can find the template definitions on GitHub and MRABLE idea live templates. So you can see I just updated them an hour ago and you should be able to use them if you import them to Intellj as well. So to begin we're going to start at Spring.io. So we could go to that site and pick out DataMongoDB Reactive, Web Flux, DevTools, and Lombok but I also have just an alias that you can see there that I've created for these. So let's move everything over here and we'll go ahead with just Web Flux start. So that downloads a demo.zip that has those dependencies in it. I'm going to create a Web Flux React directory, CD into that and then unzip this demo to Reactive Web. So if I CD into Reactive Web, I can open that up in Intellj. The API I'm going to create is just going to be a simple profile service that has a profile with an ID and an email and that's about it. You can also persist them, save them to the database, add new ones, all that kind of stuff. So to begin I'm going to create a profile entity object in the demo directory here, call this profile and like I said I'm going to be using live template so I have this Web Flux entity here and it's profile. Then we'll also be creating a repository for it so profile repository. Got a spell right? Web Flux repo. And so this extends from ReactiveMongo to the repository which has a number of CRUD methods, create, read, update, delete to make it very easily to define our API. And I'm also going to have a sample data initializer. So this is just going to put some fake data or some basic data into our database. So you can see here it implements application listener uses that profile repository and when the application starts, first of all it deletes all the records in the database and it goes through and it basically uses a flux to add new profiles based on A, B, C and D, random string and then that email. And then it does a find all and it subscribes and prints them out. So how Reactive Programming works a lot of times is you actually have to subscribe to the endpoint to get it to actually kick back information. So that's what we're doing there. And at this point we should actually be able to start our application and see that information. So I'm going to set the demo as active profile here because we did specify that right here. This only kicks in and it only initializes when we're in a demo. You'll notice we're using Java 11 for this and it fails because it can't connect to MongoDB. So the cool thing is this is Reactive. So most applications, if you start them, they can't connect to the database they fail. So with Reactive Programming, if the database happens to come available, it'll actually go ahead and start it and connect to it. So I'm just going to show this in a different window over here. So if we do PseudoMongoD, it starts up on the left there and actually down here it starts up as well. So you can see that sample data initializer kicked in and it saved those profiles into the database. So REST API isn't that great if there's no API. So we still have to create that. We'll start by creating a profile service. This will act as our middleman between our controllers or our resources and our repository. So you can see here it's just a profile repository as a dependencies, also application event publisher that'll publish when we add new records. We can go down here and say comment that out because we're not worried about publishing new messages yet. So now that we have a profile service, we can create a profile REST controller. This is a classic Spring MVC style. So you can see here this uses that profile service, injects it as a dependency and we're using a different profile. We're using the classic profile. If we call getAll, we return a publisher. So that's how most of these work. GetById, same thing, returns a publisher for the profile. Create, we'll go ahead and create a new one. Build it. And then the deleteById, we'll call the service as well. And then updateById does something similar. So now we have that in place, we can go and modify this to be our classic profile and restart it. And now we should be able to hit that profiles endpoint. You can see we're getting that data back. And we can also do I'm gonna break this one off and minimize it. We can do things with HTTP, I always say it wrong, HTTP. That's how you say it. You can go to profiles and you can see in that way you can also enter a new one. For instance, HTTP post to 8080 profiles, email equals mat.rable at octa.com And if we look at our profiles again, you'll see it's been added. We could also do a put to this ID. And we could change emails. For instance, email equals mrable at gmail.com. And now we look and see that that's been updated. We could also delete it. HTTP delete 8080 profiles. And now it's gone. So you can see we have a full REST API using the traditional REST controller from Spring MVC. The basic difference is that we're returning publishers instead of response entities. And so to do it more of the webflux way, we can actually create handler mappings and endpoint configuration. But before we do that, let's do this event stuff. So we're going to create a profile created event. Just a simple event that extends application event. Then I'll create a profile created event publisher. You can see here this uses a executor. When the application event is received, it offers it up and then it accepts it and that executor goes ahead and publishes it. So once you have that in place, we can update our profile service to actually on success of creating a new profile it will publish that event. And now we can use the traditional webflux handler. So profile handler instead of the REST controller. So this guy, you can see the class profile handler. It's just a component. It uses that profile service to get the idea and read the response. And here's the default write response and the default read response. So it's just setting those to OK and setting it to application JSON and doing it in a webflux way. The other thing we need is a profile endpoint configuration to map this class or this handler. So profile endpoint configuration You can see this specifies the route. So it says for profiles, go to that all handler. Profiles idea uses the method handles to go to that handler and those specific methods. So that's all pretty straightforward. We also need to create this case and sensitive request predicate. So it actually doesn't matter if we do uppercase or lowercase profile or even have a mix of characters. So this guy is pretty straightforward. It's just how you do request predicates with webflux. So you can see here it uses this lowercase URI server request wrapper and just lowercases everything. So case doesn't matter. So once we have that in place, we can go ahead and restart and make sure we're using demo instead of classic. Now we can try that profiles endpoint again. Make sure that works. Yep. And if we were to do HTTP profiles, that all still works. Now we're using the handler instead of the rest controller. I'm also going to create a web socket that shows when these new profiles are created. So I'm going to do that by creating a web socket configuration class. Web socket configuration uppercase web socket. So this is what defines that executor that the publisher is looking for. And then we have this handler mapping that just maps WS profiles endpoint. Web socket handler adapter. And this basically from that publish it maps the source of the event which is a profile and just returns it as a JSON object. So that's what this session send does with that message flux. So now what we can do is we can create a web socket page so a client per se. So we'll call this static WS.html. And this is just a simple HTML page that uses a standard web socket to talk to local host AD80 WS profiles. And when it gets a new message, it'll basically tell you. So we can create a new batch script that'll create these profiles for us. So you can see here it just picks a random email and appends a letter onto it and posts it. So it doesn't really append a letter it just uses random. So now we can open a terminal window we probably want to restart everything. And we can run this create and we'll navigate this one to WS.html. I really don't see anything there but when we run this, you will. There's a new message from the server. You can do it again and there you are. And then if you want to see if those have been added to the list of profiles you see they have. So the other thing we can do is create a server sent event so server sent event controller. And this guy uses a flux of the profile created event. And you'll see we have that publisher and we're sharing it so we can access it and get those messages. And then an object map are just from Jackson to do the taking a profile and turn it into a JSON object. The path is sse slash profiles. You have to have this media type or it won't work and then we're just returning a flux of strings. So as the events come in it's just going to write those out for us. So now we can restart again. And now we can open up a connection to HTTP, AD80, sse profiles dash s. And so now it's listening for new profiles coming in. If we create them you'll see there they are. So we have server sent events working, we have web sockets working, we have spring web flux. Now let's turn to react and create a react app that talks to this. So I have a few shortcuts to make this simpler. The first one is I have two aliases so let's look at create react app aliases. Alias CRA. So that one I use MPX create react app and then whatever I pass into it. The next one I have is TS which adds the typescript dependencies. So create react app 2.0 and above basically allows you to simply add typescript and then it'll recognize typescript in your project and as long as you have these dependencies everything will work. So I can do create react app, call it react app and then I can do yarn start. We aren't in the app, you have to be in the app so yarn start here. You can see that's very basic react app that you can generate. So back to our tutorial here. So now I'm going to add the typescript support. So this is CRA TS as my alias. Now we can open this directory up in IntelJ as a separate app. And so I'm going to start by just modifying this app.js. I'm going to make it into a typescript file. So rename sx and then I'm going to add a component didMount so I have a shortcut for that called react fetch. So this is going to hit localhost 3000 and the profiles endpoint and then it's going to set the state of profiles and is loading to false after that happens. So to make this all work we're going to create a couple interfaces. So interface profile this is going to match what's on our server so ID is a number email is a string and we're also going to have app props or interface app props. It's just going to be empty for now and interface app state and in the state we're going to have those profiles and it's array of profile and is loading as a boolean okay and then because we're using typescript now we have to put these in on the class signature so app props state need to specify those in a constructor initialize it to basically not have any data in the beginning the profile is empty and is loading as false you have to call super when you do this. So now we have all that we can go into the render method and change first of all we have to have a way of telling people it's loading right so this basically grabs the profiles and is loading from the state and then if it is loading it just shows the loading messages right no reason to show the rest of this. So then in here I can change this to a list the list of our data that comes back so profiles.map profile object we'll put a title of profile list here so now you can see we're going to render that h2 with profile list and this is how you basically do looping in react where you map it and then you have to have a key and then we'll display that actual email. So to make all this work you notice we're going to localhost 3000 so this isn't going to work right away because 3000 is actually the react app but what you can do to get around cross origin resource sharing and trying to talk to localhost 8080 is create a proxy. So this is just going to proxy everything from localhost 3000 or the endpoint to 8080. So now we can start this app you'll see a detected type script in the project now it's going to reload everything and we should have our list of profiles. Okay so now we're getting those from the server side so if we wanted to we could go to our server and restart it so we don't have those random ones in there. So we'll just go ahead and restart it right now we just have those basic four so we can go back to our react app and now the next thing I'm going to do is basically turn what we have an app.tsx into its own component called profile list so we can actually copy this and then we'll just rename everything that's app to profile list. So profile list place that one, that one, that one, that one, that one and we can actually delete all this stuff because we just have the profile list that's all we want to show so make that look a little better and then replace that last one. So now we have a profile list and we don't need CSS because we're not using any of it in this particular class. We can go back to app and revert everything to what it was in the beginning and then we can just say hey this is our profile list so I believe this really shows like the power of react and how you can easily grab a component and reference it from another component. So everything's still working over here. The next steps that I want to make is to basically show you the different techniques for getting the data from Spring Webflex and so the first most primitive way is to actually use an interval and so this basically will fetch new data every second or so and show it. The problem is it's going to fetch all the data. So react interval is my shortcut and I'm going to add an interval up here so we can set that and expire it. So you'll see here this fetch data method sets a state to loading is true and then it goes ahead and fetches those profiles and then just gets it back. Very similar to what we had before but the component did mount is the one that calls that fetch data and then it sets that interval to happen every second when the component unmounts it clears that interval so that's why we set it to a local variable. So if we were to go back to our app you can see a nice error that says cannot find global value promise. So that's because it did create this TS config for us but it's still not targeting ES6 so we can do lib and ES6 and DOM and that will fix this problem. You do have to restart the app though because you are modifying the compilation settings so in the instructions in the demo here you'll see that I expected that know it might happen. So if you need those values you can grab them there and so now you'll see it's kind of janky right? We're getting that screen flicker because it is refreshing that data every second. So that's not a great experience but we can still create a stream so let's add a new script that creates a stream of data. So this script basically will post for 120 seconds a new random profile as long as it's just running. So if I run create stream you can see those do get added when it refreshes but still it's fetching the whole list so it's not super performant. The next way I want to show you is to use RxJS so you can actually do yarn add RxJS and we want to shut this down since we're adding a new dependency. Now that we have that we can go in here and change these three methods to just be a single component did mount. So this is very similar to the last one we have to import some things here start with and then take this out and now import that. So you see up here the imports that it added are all from RxJS start with switch map and interval and what this does is it starts with the interval of saying hey every second go ahead and pipe that and start with zero so this will fetch right away as soon as the component mounts and then this switch map will fetch it every one second beyond that and then this request.subscribe you often need observables just like with web flux to actually get that data and then it sets the data locally and sets is loading to false. So we should be able to start this and whether you use MPM start or yarn start doesn't really matter as long as you have both installed on your system. So that takes a little while to compile and now you'll see if we start adding new records again it'll start appending those at the bottom but it's also not as janky right it's kind of a smooth adding of them so better than interval but still not great because it is actually fetching all of those records and replacing every single one of them. So the next thing I want to show is web sockets so with web sockets I have a shortcut for that so this uses that component did mount as well what this does is the first time it'll actually fetch all the records and then it adds this event listener for more messages coming in and then as those come in it'll just push the new one on to the profiles and sets a state of profiles. So this is a bit more performant because it's not making requests and getting the whole list back it's just doing that once in the beginning and then it's listening for new events to get added so I'm going to restart the server so we have less data. So you'll see we just have those four records now if we start creating a stream it'll just add the new ones as they're added maybe I forgot to save this so back to the server let's restart that one more time so we don't have all that data in there this is what happens when the server is down that's just because I haven't done any error handling in the app so now you have those and if you create the stream I'll start adding those as well. Why is it not working? So let me debug this and I'll come back in a minute and tell you why it's not working. Ah, simple. So I missed step six here which basically the proxy mechanism right here does not proxy web sockets so what you have to do is you have to create a set up proxy.js in the source directory and then you'll see you can use HTTP proxy middleware to actually set WS to true so I believe that might be an issue that will be solved in create react app and how you can configure in package.js or JSON but right now this is the workaround for that so you do have to restart everything and we'll restart our server as well just so we have less data so back ends probably not up now it is and now we can do our create stream again and the web sockets will start showing up there so that's all working as long as you have your proxy set up okay. So the last thing I want to show you is with event source alright so in this profile list instead of using web sockets we can use event source so react event source and this one is similar you can see we're going to 3000 profiles we're getting that response but this is a big difference right here we actually can't proxy that I found event sources with create react app so I actually have to go to 8080 ssc profiles and then use event source to handle the on message and I added this one in here because it really helped me figure out this problem because I would get the open message but I'd never get the on message so it turned out that the proxy was the problem or the lack of proxy so to fix this or to work around what you can do is on the server side you can add a cross origin annotation here on the server sent event profiles and we'll just specify that origins is htp local host 3000 and then restart it and now our app will be able to connect both on 3000 profiles using that proxy and on 8080 ssc profiles so we could have went and added a cross origin annotation here as well and accomplish the same thing so now if we go back to create react app this guy's still running okay so we just have those and now if we do create stream the event source will work just like the web sockets where when a new one comes in it actually grabs that and publishes it so that's all working the next thing I want to show you is how to authenticate with octa or how to add authentication in so a lot of the tools in this are actually spring security at least on the server side so in my pom.xml I can start by adding some dependencies so these are the dependencies I added spring boot, starter security, a lot to client, a lot to resource server and a lot to jose which is for JWTs also called jots or jsonlet tokens so once I have that in place I can go into the resources directory, rename this application.properties to application.yaml just because I like yaml a bit better and so these are the properties you'll see here there's an issuer URI created with my octa account, client ID, client secret and then these are all the spring properties so you have an issuer URI for OIDC and then you have a client ID, client secret, the scopes or you can leave these out because I believe these might be the defaults and then a resource server which I'm actually not going to use yet but just to show you how you might create similar settings if you go to developer.octa.com click sign up then you just have to fill out a few fields, these are optional down here but email first name, last name company, I already have an account so I'll just go ahead and log into say this one here and I don't even know my password, I just store in one password then sign in and then you'll go to applications add an application and you'll basically do a web application because it's spring security and the server side and you could call it web flux demo and then this will need to match a specific value in octa and then you can do implicit if you want to have React use that to get to it and that's what I'll use today but I'm actually going to use a different application that I already have configured let me show you that one so reactive web here and you'll see this has authorization code enabled also implicit, this is because on the client side I'm going to use React and actually log into octa and then send an access token to the server side and so I need to have implicit enabled to do that and then you'll see the login redirect URIs, this is what you need for spring security and it's OIDC support with octa and then this is for a tool that I'm going to use to get an access token and then this is for my react app so I've already configured all those and the tutorial that I referenced does have all these values in there so once you have those you should be good to go I'll just log out here so when I try to log into the app it doesn't automatically sign me in. So I have those guys and now what I can do is actually start things up again so first of all enable auto import so IntelJ grabs them one thing I did want to show you is if you're typing spring boot run all day you can actually go into the build configuration of your palm and specify a default goal of spring boot run so once you have that in place you can easily, if you didn't want to use your ID and you want to use a terminal you can just run nbn and it will run that default goal and the spring team likes to use tabs instead of spaces, I like spaces so IntelJ knows me well so if you see this using generate security password let's pick up the spring security dependencies and then if you go to localhost 8080 profiles it'll actually redact it along in and it'll come back to your app and show you all the profiles in there so we have the service side protected now but you'll notice it does a redirect so that only works if you're coming from the browser we also want to make it possible to send an access token from react so let's go and add OIDC support or authentication to react so I have a couple shortcuts here as well first of all, I'll just follow my steps so I don't get out of order, I'm going to create a security configuration for spring security and the reason I'm doing this is because this is necessary if you want to have like I have where it redirects to octa if you try to access 8080 profiles and allows a resource server which means you can accept an access token and not do a redirect for this to work you basically enable webflux security, enable reactive method security I'm not going to actually use that in this demo but if you want to have like pre-authorized annotations like that on your methods you would need that annotation and then unlike spring MVC where you extend a class, this just has a bean for the web security filter chain and so I start by enabling CSRF and specifying it in a cookie so the react client could read it and send it back and then authorized exchange we're going to permit web sockets and the reason for that is because web sockets don't, or I wasn't able to get it to work with an authorization header so we're going to allow web sockets to come in without any sort of authorization and then I'll change the web socket publisher so it only publishes an ID and then the client will take that ID and refetch so it's the best that I could do as far as making the server side secure and still using web sockets so I think our socket is going to be a good solution in the future and I reference it in the blog post and give links to the spring security or the spring framework issues for supporting web socket so I don't think it's quite there yet but I do have some examples in the repo if you want to go try it out and so this OAuth2 login is what does the redirect and then this OAuth2 JWT right here is what handles specifying the resource server so to make the resource server work in this application YML you need that resource server and the issuer specified here so then there's also this cores configuration source that configures cores for everything so it allows credentials that sets allowed origins to 3000 this basically allows us to make any requests from the client and directly to the server so that's all configured we can go ahead and restart the server side then we can go back to the client the React app and first of all we'll make sure nothing's running and I have a couple of aliases for installing octa react so I just do octa react and that adds octa react react router DOM and then it adds the TypeScript support for the React router DOM or the types so once you have this in place you can go into this app.txt first of all we'll add the config so this uses the config right here my same settings the same client ID and then it has this interface for octa log in log out check if it's authenticated and get the access token and then I can change this to be React security and so you'll see we specify the security from that config and then we go to a home component first since we're not able to use this one and then we have that implicit callback that's going to come back and handle the octa log in so you'll notice there's an error here that it can't find any TypeScript support in this so to work around that we can declare module octa react and that solves the problem so now you see there's no more underlines we can clean up our imports there and now we're getting somewhere so let's create the home TSX this uses that profile list you can see it down here but it passes the auth in there too so we actually have to go into the profile list and specify in the props then import that see if I can import correctly there we go clean up the imports there nope I'm fine with IntelliJ doing what's doing so now that we have that if we look at home you'll see that it uses this with auth higher order component so that's part of the octa SDK see right there and then it sets the authenticated state check authentication comes down to here and so this is what does all that authentication checking and then we have log in and log out and it renders the button so if you're authenticated it renders a log out button with the profile list if you're not authenticated it just renders a login button and that's it and so that body is then specified down here so now the last thing I want to do is just give the buttons a bit more padding so just give them a margin top and make their font size a bit bigger and then we can go ahead and yarn start and I believe this will fail but it might succeed we'll see yep it failed because I forgot to import such a small thing okay now it says welcome to react so if we click login it'll redirect us to octa but since I'm already logged in it actually came back right away so the reason that it failed is because in profile list we're not sending an access token so if we change this to the original react you'll see it's very simplistic it just goes to profiles and you'll see it gives us the same information or the same error when it fails to compile so what we need is to pass in an access token so this is a syntax for that you can see we're hitting that profiles endpoint and we're passing in the header and we get that access token from octa react stk and so now it's working and it's pulling all those in but like I said this isn't a great performance mechanism because it's fetching all of the records right instead of just the one that's been added so we can change our web socket configuration to just pass back the id so instead of writing this whole thing as a string we'll just start with doing profile we'll cast it from dot get source to profile and then we'll create a map let's just string string call it data and then we can go ahead and put the id in there and then return object mapper write value as string and just put data in there so now we'll just be getting the id back and then what we can do on the client well first of all we'll want to restart this on the client we can use web sockets again and so the difference here is we're still going to be making that original request to profiles right with that access token but then this web socket request is going to be unsecured but we're only getting the id so I don't think that's terrible right so we'll get that id from this event dot data and then here's the id that we'll pass in and we'll pass in those headers again and then we can basically push that new object that comes back on there so a little chatty and I think our socket will solve this but from what I've seen it's not quite ready yet let's see so now to create a stream we actually have to go we can use this oidc debugger so it's already got some information in here that it kept for my last session and since I have implicit flow enabled it allowed me to get an access token this way so once I have an access token I can go into this create stream and I can say access token equals this guy and then as far as the HTTP post I can do authorization, bearer and access token and now I should be able to run create stream and it'll work I've seen this error a few times you see that says invalid token this is claim is not equal to the configured issuer and really dug into that and figured out why but I know that if I restart it should work this time there you see it's actually creating the records and they're showing up here so there you have it I hope you've enjoyed this demo of react web sockets and spring web flux if you want to learn more about this I suggest you subscribe to the octa developer blog you can also find us on twitter at twitter.com slash octa dev so whenever we post new tutorials or new things on our blog we always post a tweet as well thanks for listening and I hope you have a great day