Realtime Chat App | React, GraphQL & Websockets

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] so in this video we create this multi-user real-time chat system but before we get there i just want to say thank you brad for the opportunity to connect with your audience i think it's really great you're giving smaller youtubers this opportunity okay my name is jack harrington i youtube as the blue collar coder and i cover friend topics all the way from kind of basic to intermediate to advanced examples like this multi-user chat system that uses graphql subscriptions web sockets and eventually a new feature called module federation that's built into webpack five it's really cool if you haven't heard of that i think you're going to want to stick around for that okay so here how are we going to do it so step one we're going to go build out our graphql server it's going to be pretty simple just reading and writing messages then we'll use in step 2 apollo client to go and build out a react app that uses polling to connect to that server and that's not particularly efficient so we're gonna go back in step three to the server and upgrade it to a subscriptions model and then in step four we'll go and upgrade the client to use those subscriptions and then you're gonna do in step five something really cool and share that chat component to another application live using webpack five's module federation feature it's really cool but i've talked enough so let's just go jump into the code all right so here's our app that we're going to build and it's actually side by side we're showing two versions of it localhost 8080 on on both sides and it's a basically chat window it's got the chat list at the top and then it's got a three column section down below the first column has who you are and you get to just define that on the fly and the message you want to send and an ascend button although you can hit return just make it make it easy and you can see immediately i click send and boom it's over in the other window no problem i can add a third person to the party down here i'll add joe and you can see when i type in joe it says well you're not in the conversation yet so all of the other messages which are from jack and mary go on the right hand side and then anything i type in is gonna go on the left hand side all right looking pretty good so we're going to use for this is we're going to use graphql and to make that easy on ourselves we're going to use a starter kit called graphql yoga so let's go build that server i'm gonna create a new directory called chatmatic it's gonna have well three projects in it but we're gonna start with server and we're gonna emit that package json and then add in graphql yoga okay looking pretty good let's go check out that package.json and go create a script that's going to start our server and we're going to create a new file called server.js and into that we're going to bring in graphql yoga and from that we're going to bring in graphql server let's go create it and then we'll call method on it called start and start is going to take a function which callback and part of that is the port so that's going to tell us what port it started up on and we'll just console log that out server startup on hp loghost make that template string okay looking pretty good now every graphql server needs types it's got a schema so the first thing we need to do is define what a message looks like and the way that we do that is by saying type message and then in curly braces we put in the different fields that are within message the first one is going to be the id it's going to be unique ascending id and there's a special type for ids capital i capital d and then if i put an exclamation mark that tells me that the field is required so this is saying that i have an id that's required and then i've got a user which is a string which is required and then content which is also a string now how do i get these messages well i've got to have a query type so i create a query type that has within it a a key for messages and that's gonna return an array of messages and that's signified by those square brackets and i'll add that into the graphql server definition by saying that that's our typedefs giving it the same name so make it easier on ourselves and then we're going to give it a set of resolvers as well so it's basically saying okay now you got your types now how do i actually get the data and that is done using resolvers and the resolvers kind of match the keys that are in the type definitions so in this case we've got a query and then within that we've got those messages so resolver is a function and in this case it's got to return an array so well let's go making a new array called messages and then we add those resolvers to the graphql server so now we've got the types and how to go get them all set up so let's start our server and here's a really cool thing about well most graphql servers but graphql yoga as well they have this graphyql interface built right in so we can start playing with it right away so i bring it up and if i'm not making a request from like a fetch i get this cool graphql ui so let's go make our first query and the syntax for that looks like this you give it a query you say i want messages you give the fields that you want and then you execute it in this case it's not too exciting right we don't have anything in messages so we have to go create a mutation now mutation is essentially like you know post in the rest world and what do we want to do this we want to post a message a new message so we're going to say that post messages will take a user as a string hat is required that's the exclamation point and also the content and it's going to turn an id you know what what id was created from this new message it could return anything it could return the message it's whatever you want and we've got to go add a resolver for that so in this case we're going to say that it's a mutation and it's post message and now that function actually does in every case take a bunch of arguments and the first one is the parent which would be whatever the container is in this case that's that's not going to be anything this is the root of the tree which is empty but it also takes arguments which in this case is is user and content and then we're gonna go get the id which is just the length of the array and then we're gonna go push that content the id the user and the content into the array and then return that id all right let's restart that server because we're not going to pick up those changes until we restart the server and we can rerun the same query but we'll find again an empty array so let's make a new tab here and say that we have in this case a mutation it's not a query in this case we want to do the mutation and we'll say that we want to post that message we give it a user of jack and a content of hello great and it looks like it was successful it returned a zero which was the size of the array which is the new id then and we'll go add another message goodbye okay now we get a post message return of one and let's go back over to messages hit play again awesome okay this is really cool so just in the few first few minutes here now we've got a working graphql server that supports a schema that you can now request data from and also add data to dynamically it's really pretty exciting okay we've got our graphql server running it wasn't that hard which is great so the next thing to do is to go build a ui based on that so we're going to use a component library called shards it's new it's pretty cool it's lightweight and we're going to use apollo client to go and connect to the server let's go try it on the code but this isn't a great ui obviously we want to go and create our chat ui to go on top of the service that we just created so i'm going to use a starter kit that i built it's kind of like a pair down create react app all it's got is just react and babble but it is based on webpack 5 which is important because at the end of this video we're gonna use an exciting new feature in webpack five called module federation i'm gonna go create another terminal window in my vs code and i'm gonna go back up a directory and do mpxd get and then give it the url of that project and dget does this really nice thing it basically just doesn't get clone and then it removes the the get directory it's a d getter but it's really nice very convenient way to start up a project and we'll do that off the main branch and then we'll call this new project client it's our chat client all right let's go close a few windows here and then start taking a look around at what client is so let's go take a look at our webpack config for this project you can see that it's fired up on 8080 all really does is apply babel to our js and then bring in any css we want using a style loader and then there's also this module federation plugin that we'll get to in a bit and then the html webpack plugin which basically gives us our index page okay let's go take a look over the code we got index.js which is the booter it's just going to import the app file it got some pretty simple css and then we've got our app and it just basically imports react and react dom brings in that css creates a really simple component called app and uses react on render with that app component to render it into a div with the id of app in our index page okay let's start that up hey it looks pretty great okay a good starting point for us so for our ui toolkit we're going to use a new one called shards very lightweight framework so let's bring that in and we'll also import some css to support that i think it uses bootstrap css kind of all right then sure and then to manage our connection with the graphql server that we just built we're going to bring in apollo client so some over here in the apollo client docs and all that is in the description by the way so just check out the links in the description and all of these links are in there for all this so let's go and follow their instructions to install it just bring in apollo client and graphql and just to make sure everything's cool just fire that up again looking pretty good great so what do we want to do well we want to go and first connect to the graphql server so we need to create a client for that so we'll scroll down a little bit we'll grab this code for creating a client and you're going to paste that into a new file called chat.jsx so this is going to be our our chat widget the app's job is basically to render that chat widget onto the page the chat widget itself is going to be in this new file we'll change out that uri for that apollo client so that it points to our graphql server and now the next thing we need to do is we need to provide that as context to any components inside of our app so we'll go and bring in the apollo provider and this is if you're familiar with redux this is very similar to that there's a redux provider that provides that state down in the tree so create a chat component and then we'll wrap that in an apollo provider where we give it the client as a property so now let's go and port that into our app and now we get a very very small i'm a chat window that just means that we've yeah we're running everything's cool there's no nothing's exploding yet but we actually haven't done anything we really haven't made any requests to our graphql server so that's what we need to do next so how do we do that well let's go over here so let's go down to requesting data and we're kind of following along with some of the documentation here this is a really nice well-documented site for apollo client pretty much everything apollo really and so we need to do is also bring in use query and gql from apollo client now gql is this handy little helper function which basically manages string templates that are filled with the graphql query language code so we'll create a new constant called get messages and we'll wrap that in one of these gql templates and we're just going to go back and we're going to go grab the code that we did right we have this nice query let's reuse that so we'll go grab the query from 4000 drop that in there nice looking pretty good and now we just got to run it right so we're going to create a new component called messages that's going to be our display of messages and it's going to take a property called user and user is going to be who our current user is so that's going to allow us to show on the left-hand side if it's not my messages and then on the right-hand side if those are messages that i created but really the important part is let's go make that query so we're going to go use that use query hook and it's going to give us back data it actually gives us back a lot of things but i'm just going to use data in this case and then we give it that get messages query let's say we don't have any data then we're not haven't done anything yet we haven't made the query so we're going to just return null but if we have then let's just return the json stringified payload right what'd we get back hey okay that looks pretty good so that is the return from the server so we're actually making the request and we're getting back the data and we're putting it on the page really cool i'm gonna go see that we're making the request we can go over here to our network inspector panel and we can see that we're making a request to 4 000. we see the request going out and the data getting back that's great it doesn't look so good though i don't think anybody wants to use json as a ui so let's go and bring in some components from that shards react library that we brought in so the first one i'm gonna bring in is container and then we're gonna wrap the page effectively in that and that's gonna basically just kind of center everything and now for the messages we're just gonna go map through each one of those and each one has an id a user and some content and then we're going to start styling some stuff so every row this thing is going to be a flexbox and then we're going to decide whether we want to justify it to the left where if it's not me or to the right if it is me but of course we have two users now we got the user from the property and we got the user from the actual message itself so we need to disambiguate those so map user to message user and where they match meaning that so this is a message from me we're gonna justify it as flex end which puts it over on the right hand side and if it's not me we're gonna use flex start which puts it over onto the left hand side add a little padding to the bottom and now we'll create the content div so that's going to have the message body itself it'll make that pretty we'll give it a background where the background is kind of a greenish thing if uh it's me or a grayish thing if it's somebody else and then for the font color we're going to use white for me and then black for anyone else and that's going to give us a nice contrast and we'll put a little padding on it give it a nice border radius to make it roundy and we're going to say that our max width is 60 right so that means that there's gonna be a little overlap if you get really long messages it's gonna overlap in the middle it's gonna look really nice this is gonna look nice all right let's go take a look oh it's looking good already that is pretty so let's see if that message user logic passes by just changing out the username so in this case i'll change the user to mary which is not the person who sent those messages and it shows now if i marry now jack's messages show up on the right hand side so this looks good but we're missing that little circly thingy in there so let's go make that and we're gonna say if i'm not who sent the message and we're going to put in the circle by creating a new div in here and it's got the the username we're just going to slice off the first two letters out of that and then uppercase it and we'll make it a 50 by 50 circle with a little bit of margining on the right hand side just to move it away from the message all right now put a little two pixel solid border around it give it a border radius of 25 that's going to make it a circle because the width and height are 50. we'll align the text in the center and we'll give it a nice big font size let's take a look uh looking pretty good it's up a little bit so let's go and add a little bit of padding on that oh oh that looks really nice okay so the next thing we need to be able to do is post a message to this thing so we need some ui for that so we need a row and a column we're going to use that for layout and then we need the form input which is the input field and a button for that send button and we're just going to manage this out of chat so we're going to create some state and use good old-fashioned react use state for this and we're going to say that the user is well me and the content is nothing and now that we have a state and we know what the user is let's go and set that user from the hard-coded mary to the state user and now let's create a row where we've got three columns in it where the first one is going to be a size of 2 out of 12 and have no padding and then within that we're going to have a form input field you have a label of user a value and then i have the value which is the user key within state and then in onchange we have a callback that takes an event and then calls state set to go and reset the state to have the current state where the user is set to the current target value on that event which is essentially the value of that form input okay that looks pretty good so we need to do almost exactly the same thing for the message we're going to change out the sizing a little bit make that 8 wide out of 12. i guess that's what three quarters and the content and we'll then change the state set looks good let's try this out all right looking pretty good and i noticed now when i change out the user it kind of flips immediately from side to side so i'm at jack and i change that out boom it goes over the other side really great and the last thing i need is a button to send it and we'll just call some onsend function that we're going to go create so we're going to also make it easy on ourselves we're going to handle somebody hitting return in the content form field and that just means we need to look at the key up and then if within that the event has a key code of 13 which is return we're going to call that onsen function so let's go and make that onsen function first thing we need to do hey if we don't have any length in the content that don't send anything come on no no blank messages so then once we've sent it we're going to go and reset the content to yeah blank that's that's a nice thing to do right so how do we go and run a mutation so let's go over to our handy apollo client documentation again let's click on the mutations section and we can see that there is this use mutation hook so let's go and get that and turns out hey we've already got some code for mutation so let's go and grab that out of localhost 4000 again and we're going to use our gql thing but this time we're going to call it postmessage but here's a problem right so we don't want to go and always send you know jack goodbye that doesn't make any sense right so we need to replace that with a value so in this case we're going to say that user is going to be dollar user and content is going to be dollar content well where does it get that well that's going to come in from the variables and we define those right at the top so you can say mutation and then parentheses dollar user is a string and dollar content is a string and that will tell graphql to expect that there will be variables named user and content and they're required because of the exclamation point and then it's going to map that to the fields user and content on that post message and you can also see that kind of over in the documentation over here and they use add to do and it's going to take a type as a string so let's look down the documentation a little bit we would get back an array and the first item is this add to do which is actually going to do the work but we also get the query makes sense let's go put it into our code so we're going to call it post message and then we're going to use mutation and give a postmessage so how do we invoke that well you give it an object and the object has variables as a key and then the variables you want so let's go drop that in there post message and then within that variables and we just send the state right because user and content match up awesome let's go try it out i'm going to hit send and the content disappears that's good let's uh refresh now and excellent okay so it's working that's good but the fact that it didn't appear is not great right that's that's not great ui so let's go and fix that so if we go back to queries you scroll down a little bit we'll see that there's an option for polling so all we need to do is add in this poll interval on our query so let's go back up here to messages and then just add in an options object that says poll interval is 500 sure why not that sounds good and that basically means that every 500 milliseconds we're going to refetch that query so let's type in this one and boom there we go nice but let's have a look over at our network inspector and see the damage that we have wrought look at that okay so that's now every 500 milliseconds we're making another query and that's that's probably not great okay we've got our client running that's great but it's doing this polling thing like every 500 milliseconds and that's just inefficient i mean if there's no messages waiting for you then you're just hitting the server every 500 milliseconds for no reason which even if you get the protocol down and you're not on not sending all that much data it's still a lot of overhead and it's still a lot of uh api requests to the server that are there for no reason so how we're going to fix this we're going to use the subscription system built into the graphql standard and create a websocket connection between the client and the server and it's just really cool let's go check out in the code how that's done to start changing out the server so that it's a subscriptions model we're going to first stop the server and we're going to bring in pub sub from graphql yoga and that's a publish subscribe handler for this graphql system and then we're going to define a new type and that type is subscription it's just like query and mutation it's a special type and it's going to have the same thing you can subscribe to messages and in that subscription and this is probably the most complicated code we're going to do here we're going to have a subscribe function that's going to take a parent args and then it's going to take the context which is going to contain a pub sub object that we haven't created yet so let's go create that we're going to create pub sub by just saying we want a new pub sub and we're going to add that in as context so the first thing we need to do is define a new random channel so we'll just go use math random that's going to return zero dot something some random number so we'll slice off the the zero dot and we'll just get the number and it's going to give us a nice little random string there and then we're going to return effectively the pub sub async iterator for this channel and so in addition to that we also need to keep a persistent list of who's actually subscribing who's on all these channels so we're going to call that subscribers and then we're going to have a a new function called onmessage.update which allows us to add a new subscriber to this list of subscribers so call that onmessagesupdate and it'll take a function which is our subscriber callback and we'll just push it onto our list of subscribers and so the first thing we need to do is say hey cool all right you've shown up you've asked for a subscription on messages so we will go and add you to that so go and give it the function and that callback is then going to use pub sub publish on that channel to send you a message hey here's the new messages so we'll use channel and then we'll give it the content of messages but will also be really nice we will set a timeout so that it automatically sends it the first time when you start publishing so we'll do set timeout and we'll give it exactly that same callback and then we'll do it on zero which means on the next tick we're gonna go send you that data you've subscribed here's the data boom there you go you don't have to wait for somebody to actually go and post a message in order for you to see the new messages now there's one thing left to do so we need to go over here to the mutation and we need to alert the system when a new set of messages out there so the way that we do that is we iterate over subscribers and then for each one of those we just call that callback there you go so let's start up our server all right so now we're going to try this out the first thing we're going to do is we're going to post a message cool and we're going to create a new tab where we basically create our subscriptions we go go create a subscription here's messages we want id and user name and hit play and now right away we see what we just posted right we see that we posted jacket by let's go over to post message again we'll change that out to hello and now graphic ql is automatically showing the new content because we're subscribed which is really cool so now we know this is going to work if we can make the client sing this song all right so we know through our graphql ui that we can speak subscriptions between the client and the server which is great and of course now we need to go make our ui go and do that but before we get there let's talk a little bit about how websockets actually work so a website when you when a client requests a website connection to a server what actually happens is the first thing that happens we do an http connection just a standard http request but as part of it we say hey we want an upgrade and if the server can support that then it flips around the connection to be this live continuous connection between the server and the client and that allows then the graphql protocol which sits on top of this to accept incoming data from the server when subscriptions are updated which is really cool all right so let's go try it out on the client and see how this is actually going to work in our react app so how do we make the ui now do that subscription so go back over to client and go over into subscriptions and then our handy documentation also talks about how to do the client side so first thing we need to do is add in the subscriptions transport ws library so let's go and yarn add that and the next thing you need to do is change out our link so let's go and bring in this import statement which is going to bring in websocket link and then we got to create one so we'll call this link and then instead of localist 5000 we're going to say it's on localhost 4000 because that's where our server is and now we'll add the link to the client and let's start it up all right looks pretty good all right so it's working which is good but i don't think that we're using that subscription yet because we actually we're just still using queries so our queries are now running over the websockets which is really interesting so let's do use subscription instead of use query and we'll say subscription instead of query and then we'll change out use query to use subscription and we'll get rid of that polling we no longer need to pull yay okay and let's type in something hey and it works right away that is really cool and you can see it's instantaneous boom i hit it i hit it and it's done no problem so let's create another window and just kind of put it down to the side there and now you can see how instantaneous it is like i just type i've got sally and she says something and it just instantaneously pops up on both sides and we can even go back to our graphql interface and show that it's also subscribed it's like another chat client it just happens to be showing json how cool is that all right so we've got our efficient ui that uses web sockets and only gets data as it's needed which is awesome but it wouldn't be like me to leave it there so we're going to kick it up a notch by going and using web pack five's module federation technology to share this chat component with another application so module federation is really interesting if you're in the kind of medium to very large business context you might be using what's called a microsite architecture which means that your site is actually composed of a bunch of smaller apps and in that model sharing code can be a little problematic so module federation allows you to take parts and pieces of your application and share them directly out of your app which is really exciting and it's a live sharing system so that means that when we update the chat mechanism that we have in the current client app it's going to automatically update in the new app that's consuming it which is really neat all right let's go jump into the code and try it out okay so now we want to go and integrate this thing into another application we want to have yet another app so let's go create another terminal in our and we're gonna use the exact same deget as before but this time we're gonna call it homepage so our homepage is gonna have a chat i'm guessing this current chat client may be on a on a customer support page i who knows so we'll go into home page change out the package name and we'll go and change out the webpack config so first we want to be on 8081 and then we're going to start messing around with our module federation plugin and so we'll call this current app home by changing name and also the library name and that's all we need to do while we're a consumer home is going to consume clients chat so now let's go and tweak the ui a little bit we'll go over to the app on this one and we'll just go create some simple stuff we'll add in our shards library bring in the css for that bring in the container make a couple paragraph tags make an h1 that says chat and then i'm gonna put in a placeholder essentially this is where the chat one is supposed to go and then we're gonna go bring in lorem ipsum just to make it you know so we can visually see that there's a difference between these two things and we'll start that up nice okay so pretty standard got a little placeholder in here and now we've got that chat window here thing so that's what we want to replace with the chat so how are we going to do that we need to get the chat code from another app entirely so now let's go over to the original client app and modify its webpack config so we're going to go down into the module federation plugin and we're going to say that this is now the the chat app and we're going to expose our chat component and the way that we do that was we add a new key two exposes called dot slash chat and then we give it the source that we want to expose so in that case that's the whole chat component and that includes all kinds of stuff it includes apollo provider and oh all of that it's a fairly heavyweight component now we need to restart that cool looking good but now what this has done is invisibly added this new file called remoteentry.js and that's a manifest of everything that that 8080 chat client app is exposing to the outside world so it looks like this and you can see it's got slash chat in there and it's got source chat so it pretty much has what we've asked it to put out there so let's go and grab that url and now we're going to go add that to the index page of the home page right in the head we're just going to bring that in script source remote entry and we're going to import that component just like this we're going to just say import chat from chat which is the remote name of the client and then chat which is what we said in exposes i'll bring it in here just drop it in there just like that just like we did in app.jsx in the client app and now we can see that we got an error chat is not found hmm okay so we need to do is modify the webpack config to basically say oh there is this chat out there so let's go and modify that module federation plugin to say that we have a remote for chat so just go change tweak this remotes key and just add a chat chat is chat start it up again and there it is now we're importing chat as a react component this is not an iframe it's not anything like that it is straight up the react code from the other application automatically brought in live at runtime and brought into our app and run and it works so let's go make a change over on client which is still running to go and tweak that send button because it's not taking up the available space so let's go down here to the send button and make it with 100 and we go over to 8080 we can see that it's changed right away because of the live reload but 8081 doesn't know that it's changed so if i go back over to 8081 which is our home page and i hit refresh boom it's updated all right so we're looking at live code let's try it again just just for giggles let's go change that green to like a blue big old blue all right boom big old blue just like that kind of gaudy but okay let's go see on 8081. i hit refresh and we get the new code with the new big blue nice gorgeous module federation is super cool all right well i hope you enjoyed that i enjoyed making it i hope you learned something new maybe something about graphql graphql subscriptions or this really cool module federation system which i'm really excited about actually wrote a book on it and if you have any questions be sure to put those in the comment section down below i'll be watching if you like the video hit that like button if you really like the video go to my channel which is also in the description and check out some more videos just kind of like this and in the meantime as i always like to say at the end of my videos be happy be healthy and be safe
Info
Channel: Traversy Media
Views: 107,558
Rating: undefined out of 5
Keywords: react, graphql, react graphql, apollo graphql, websockets, graphql subscriptions, jack herrington, module federation
Id: E3NHd-PkLrQ
Channel Id: undefined
Length: 40min 22sec (2422 seconds)
Published: Mon Aug 17 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.