Transcription
Welcome to this Moshia tutorial. In this video, we're going to talk all about how Mosha works and how you can use it to create sophisticated backend applications with great developer experience. MOSA is sponsoring the channel. I had a great time using them and they've been blowing up here on GitHub.
But in case you haven't seen them yet, it's a multi-language backend framework. So, they allow you to use not only JavaScript or TypeScript, but also Python. And with it, you can create API endpoints and background jobs, workflows. You can even stream without having to set up your own uh websockets or server events. And you can build these AI agents and it's built around a single core primitive called the step and also you get observability out of the box as well.
So you get a workbench basically a UI that gives you a good overview of how your backend app is structured with tracing information. So in the actual runs or invocations on the back end you get information about that as well. Also you can trigger your API endpoints from there as well to test them out. So you do not need a separate API client for example. And although you typically do want to have your own database, you do get some state management out of the box as well.
So actually part of forcel's open-source program and they've made it a very good developer experience for the back end. So on the front end, we have already seen how react has completely taken over uh because previously we were using uh jQuery or even vanilla JavaScript and you would still have to do a lot of things yourself. But then react came along with the concept of components and state and it made developing front-end applications much easier. And now with Mosha, we get something similar on the back end side of things. So previously, you had to combine a bunch of those disjointed services together yourself to get something similar. Now you get it out of the box with Mosha. You can read more about that here in their manifesto. It's actually a really interesting read.
Now, I've worked together with Mosha on some videos here in the documentation, which I highly recommend you go through as well, but I want this video to be a more all-in-one tutorial in which we look at an actual project, how you can build it from scratch, and learn all of the fundamentals here. The project I have for this video is a live polling app. So I'm showing a UI here, a client. This is a Nex.js app because with Mosha we built the back end side and at some point you may want to have a client or front end for your back end for your back end app as well. So we will use Next.js in this video for that. Although it works with your other frameworks as well like Tens start. I actually have a different video on that with Moshia or other frameworks.
Now what should a user be able to do in here? They should be able to create a poll. So, I can create a poll like what should we do next? Right? Maybe you're asking your users which features they want to see, right? Maybe feature one or feature two, right? I can create a poll here. I will be redirected to the individual poll page. So, this is the page where people can actually vote. I I get a URL here that I can share with others. They can go to this page. I have two windows open here on this page. Now, if somebody votes on here, the other users will will see that as well without having to refresh. Right? So now if somebody votes the other users will also see it. So if I click on vote here you can see there's going to be like a workflow here where the vote has to go through a couple of different stages or steps but ultimately it will be finished. And you can see now that the results here are updated for the person who voted but also the other people that are on that page will also get the update here. So they can also see that there was a vote for that. If I click on feature two here on this uh side of the page on this page you can see it goes through that uh pipeline again but ultimately it will be updated for the other users as well on this side right so now you can see it's 50/50 right so just this alone traditionally would have would actually be a lot of work you would have to spin up API endpoint with some framework and then perhaps some kind of other library to have like an event driven workflow and then you would need something like websockets or serverside events and how to set it up so that other people can get it streamed in the results you get all of that out of the box with Mosha as you'll see.
So, let's actually try building the Mosha back end for this. Where do we start? Well, a user should be able to create a poll here from a client, some UI. And this data needs to be sent to the back end, right? So, we would probably want to have an API endpoint. So, let's start there. Let's create a new MOSA app and let's spin up an API endpoint that can receive incoming data. And then we'll build out the backend app first and then later we'll add a front end as well. But, I want to focus mostly on the Mosha back end in this video.
All right. So I have an empty workspace here in my IDE and we don't have anything here right now. Now let's actually start off with the folder structure here because we will have one backend app and in this case we're going to have a front end app as well. I like to separate those out in separate folders. So we will have one motion application in this folder. We are then going to have a front end app as well and we're going to use next.js in this video but again works with the other frameworks as well. Quite a common structure back end and front end separated. If you are not going to have a front end, then I would not do this. I would just put it directly in the root uh folder here.
So now I will navigate into the Mosha app. And what we can do here is spin up a new Mosha app. We can do that with this command mpx motion at latest create. And since I've already navigated to the Mosha folder, I want to put all the files directly in there. So let's go ahead and do that. Now they offer you a tutorial version as well. So if you're new to Mosha, I actually recommend that you first try that. I will go with the TypeScript starter in this video. So, it's going to create a bunch of folders and files and install the packages. You can see it's going to add some AI agent files as well. So, it works really well with your AI agents. By the way, you do not have to write all the code yourself. I find that the AI agents can generate the code pretty well. They also have an LLM.ext here, by the way, in case you would like to supply your agent with uh some additional context around Motion. They also have an LLM.ext here on the docs, by the way, in case you want to supply your AI agent with some additional context.
All right. So, looks like it is finished here. So, now we have a motion app in here. There's a bunch of configuration here. We have some agent specific uh folders and files that we could delete. If you're not using cursor or cloth, you can just remove those. All right. Now, by default, you get like a starter app here. So, they have an example and let's actually run it. So, we can just run mpm rundev in that motion folder and we can then open up the workbench.
All right. So, here we're in the workbench and here we have a nice overview of that starter app that you get out of the box. So they have an API endpoint. It's just a get API endpoint on the hello path. And this is a so-called step which is then connected. We can see that here with another step. But this is not an API step. This is an event step. Right? So very commonly you have some kind of incoming request into your backend app and an a into an API endpoint which then sort of kicks off a workflow. Right? So we could have other event steps connected to here as well. And the mechanism through which they are connected is with events. Right? So one step can emit an event that other steps can then subscribe to. Right now we can see the code in here as well and we also have a nice tab here with the endpoints. Now I can go here and what I can do here is I can actually trigger that API endpoint right here from the workbench as well. You do not need a separate API client for that. And if you have any incoming data, it would automatically prepopulate the body with data here as well. But we don't need that here. We just have a get endpoint. So if I click on send there, it sends an actual request. We get a response here. So we can quickly see if everything is working. And we also get some tracing details down here. We'll talk more about all of this later, but just to quickly look around here, right? So you can see how long each step took. But of course, we do not want to have this API endpoint. We want to have our own API endpoint. So let's go back to our code here. That workbench is able to visualize it based on our actual code, right? So Mosha automatically detects this these step files in the source directory, right? So that's why it was able to do that. Let's remove the hello folder though. Let's create our own API endpoint. What do we want to do? We want to allow the user to create a poll. So we're going to create an API endpoint here. I'm going to call it create poll.step. Now I'm adding a 01 in front. So it just makes it a bit easier to understand the the sequence of the entire uh flow here. But of course you don't need to add that. It's just here for the tutorial.
So then we have a step. So you compose your back end with these steps. Each step has a configuration and a handler function. So here in the configuration I'm specifying what type of step this is. Well, this is an API step. So it can accept an incoming request. So we can give it a name and we want to accept data. So it's going to be a post API endpoint. So / pulse on our back end site and then it can also emit an event and then other steps can subscribe to that event. But in this case it doesn't emit anything. Now since we can accept incoming data and you cannot trust anything coming from outside your app, we do have to validate it. You can do it both manually. Right? So here you could also parse it or you can do it here with the body schema. And this is just a zod schema. Right? So here with zod we can specify an object, right? User should be able to create a poll. poll should have a question as well as some options, right? So, we just have some rules for that. And a step can belong to a particular flow, right? So, here in the workbench, um we were looking at the hello world flow from the from the starter app. You could technically have multiple flows in your system. So, you can be specific with that. However, we're just going to have one live pulse flow. So, that's configuration. The actual implementation of the step, the actual function that will run when there is an incoming request is here is described here with the handler. So we get access to the incoming request as well as a context object. So what what do we want to do when we get an incoming request for creating a poll. We basically just want to get the data and store it in some database in the real world. Right? So here um we're just going to construct a poll object with a question and the options. So here we have the complete poll object that we want to store somewhere. Now in the real world we you would probably use a database. It is very convenient that Mosha actually has the concept of state as well. This is a key value store and it's not really meant to store data like this. You know, you would you would want to have a database for uh this type of data. So, but for this tutorial, it is a little bit it is quite convenient to put it in state. There are some other use cases for state which we will talk about later. But just know that there is a key value store that we can hook into here. And from the API endpoint, we also want to send back a response. So, if I save here now, we can see that this should have been updated.
So now if we go back to the workbench and we refresh here, we can now see that we have one uh step here post one on/poll. So if we want to try it out, we can go to endpoints. Now we can go here and you can see it's automatically prepopulated here. Now now we got a type issue here because technically there should be multiple options. So the question could be something like right what should we do and option one could be something and the other option should be something else right? So I think the options just yeah they just need to be two strings at least. Okay. So if we try out this API endpoint, we sent it. We get a successful response here, right? With status code sends back the resource that was created. We can also see tracing below here. So you can see how long this took. If you click it, you can also see some of the internal things happening in there. So what do we do in the API endpoint? We accept incoming data and we store it somewhere. I'm using the state here in Mosha, right? So now if we go to states, you can also see the state. We can still see the greetings from the starter app. Um, I can actually delete that from here if I want. We still have our poll, right? So here we're going to keep track of all the polls that are created and we can see there is one poll in here now and that poll has a question and the options. Again this is not the good use case for state in Mosha. You would use a database with this. However, if you're just quickly prototyping, you don't want to add a complete database. I think it's fine and and for a tutorial I think this is also very convenient. So I'm happy to cheat a little bit here. We'll talk more about the other use cases for state in a second. And that's how easy it is to spin up an API endpoint and also quickly test it out here. Uh really convenience here. You don't need a separate API client.
And what do we typically want to do with data like that? Well, we not only want to create new resources. At some point, the client may also want to retrieve the resource. So, we probably also want to have an API endpoint that will just return all of the polls that we have in the state. Let's create another API endpoint here. And I will call it list poles.step.ts. And actually, it's not a sequence. I'm just adding a number here just to separate them out. So, I'm just adding a number here just for the sequence of concepts I want to discuss. They're just two different API endpoints. Right. So here we have a config. Again it's going to be another API endpoint. This time it's a get though path can be the same as before cuz they have different methods. They belong to the same flow. So the only thing we want to do in here is just return the polls, right? So we need to grab it from state. So that state is something that you get in this in this context object, right? So you can do context.state and the way it works is with groups. So just the group polls has all the poles um which is what we want in this API endpoint. We can sort it in some matter for example by the time it was created. we can map here so that we're only returning the uh data or properties that we really want to expose. So you can do some manipulation there, but ultimately we're just returning the poles from this API end.
Okay, so now we have another API endpoint here. They're not connected to other steps. They're just two endpoints by themselves on the same path, right? Um, so now what else would we want? Well, we probably also want to retrieve an individual poll. So let's add one more API endpoint. We will call it get poll. So again, it's tap API. Now the path here is a bit different. We want to be able to get it by its ID, right? So we make it a dynamic portion here of the path. The handler here should find the individual poll, right? So we do need to get the actual poll ID. And now it works a bit different with state. So we say from this group, we want a particular item in there. So we just specify the ID, right? So and then that's what we return. Again, you can be specific with the properties. So we're not accidentally returning more than we would want. Um, but that's what we return here.
Okay. So now I can go for example to get polls. I should be able to get all the polls. So if I send here, I get back well a result here with all the poles. It has a particular ID here. Let me actually copy that one. So we can test the other one as well. That looks good. Now the other one if I uh it has a query param, right? So I do need to send along this param. If I send this, we get back that exact poll with that with that particular ID, right? So now a client can use this to display it in the UI or whatever they want to do. We are just taking care of the back end first here. We'll talk about the client in a bit. You can see how easy it is to spin up endpoints here.
So what we have right now is just three loose steps, right? These are API steps. Now we also want to give the user the ability to actually vote in a poll. So the voting will actually have a more like a workflow where there will also be an incoming request with an API endpoint so that the user can submit the vote. But we want to run the vote through multiple stages. Maybe we want to do some validation on the vote so that the user is not voting multiple times for example. So we can have a step just dedicated for that. verify the f, validate the vote, maybe applying the vote itself should be its own step and maybe we have an additional step after that that will notify clients that the results have been updated. Right? So in in the real world you often have more like a sequence of steps when there's an incoming request or you have like a workflow type of scenario. Let's try doing something like that.
So we are going to allow the user to vote in a poll as well. So here we accept the incoming request. Again you probably understand the structure right now. So again it is an API endpoint and the client needs to specify which poll should have this vote submitted to and we have a body schema for that and a flow. Now there's one other change here which is it actually emits an event now. So it actually emits an event and this will allow other steps event steps as we'll see to subscribe to that event and they will start running when that's emitted. Okay. Now this API step will get the poll ID and which option was picked for that. So we do need to retrieve the actual poll from our state. Right. In real world, this would be a database. So here we do retrieve the actual poll from the database. So here in the handler, we get the poll ID and ID of which option the user picked to vote for. So we retrieve the actual poll from the state here. I'm just adding a a 2C timeout here because in the real world, we may want to have we may have a request response cycle to our database. So I'm just artificially adding a few seconds of delay here so we can see how to deal with that as well. And then ultimately here, we're not going to add it to state yet or do anything else with it. we have only received it in this step, right? So, we're not going to completely process it. We're just this step is just for basically getting the data. And now we can emit an event. We can say, hey, we received a vote and we can pass along some data like which poll was voted for and which option the user picked, right? We can still return something, but now we have an event, right? So, this emit is also coming from the context object, right? So, this context gives you uh emit to emit an event. We also saw state and there are a couple of other things in here as well like a logger. So you can you probably want to use this instead of console log. So if I add logger here, right? So immediately the structuring is here. So then I don't have to write context dot I can just write the function name and then here actually we can also remove it. Now the logger is really nice because it's also integrated with the workbench. So you can easily uh view the flow of the run as well. So we may want to log something. We can say logger.info. We can say vote received for particular poll. I'm just going to add that right here. We can see that we have the API step for this. Okay. There's nothing connected here yet. We're not finished here yet. Cuz let's say we first want to validate the votes. And I don't mean validating the incoming data as in like the shape of the data, but you may you may have more sophisticated validation logic like has this user voted before or maybe in a certain time window they can only vote so many times. Right? So now we see something else for this step. We actually have a type of event. This means that the handler will run when a particular uh event occurs and we specify that here with subscribe. So this it subscribes to this topic, right? And so when this event is emitted, this handler will run, right? That's why it's an event step. An event step also gets incoming data but not from the request but from the previous step because if we take a look at the previous step, we can pass along data as well. So when you emit that, you still get that data in here, right? So this step subscribes to that. Now it itself can then also emit another event. So other steps can then hook into that, right? So you get like a chain of steps. So what we do here is we basically just do some additional validation. Um, right. We basically don't do much in here. Uh, we do we do log here. Check for example that the option ID that was specified actually exists. Right? That's another good one to check for. Right? So, you can do other validation type of logic here. It's just and I'm just adding another 2C timeout here. But ultimately, let's say, you know, we have some validation logic. The user is not trying to fraud. The user is not trying to uh do something they're not supposed to do. So, we are satisfied here. The vote is validated. Okay. Which means it can be applied, right? So, that may be another step. So we're going to apply the vote now. So this is an event step and it subscribes to that validated event that we were emitting here after we did an additional check, right? And then this can emit another event by itself, right? So then we have some implementation. Uh the exact implementation does not matter, but um we may want to update the poll, right? So we're incrementing the total votes, right? Just as an example. We can then set the state again for a final step where we basically broadcast it perhaps to certain client, right? So here we are going to have something with results updated. So this one also subscribes and emits something by itself. Although we don't need to emit something here, right? It can just subscribe to some other event and just deal with that and then that's the end of it. So this tab also event step and it subscribes to that event and it itself emits another event. But you don't need to do that, right? So it can also be empty and then you know the workflow basically just stops there. So we don't need to do it but uh that's what we have now. And now we would be finished with the entire flow, right? But let's say we may have a final logging step, right? So where we do a bunch of logging. So let's quickly add one more actually, right? So this one subscribes to an event and itself does not emit any other event. So this is basically where it ends. And the only thing it does is just use that logger that we get from the context object to uh do some logging, right? So you can decide what the boundaries should be of each step. Just like in React, if you're full stack or front end, in React, you also have to define the boundaries of a component, right? It's up to you how much you want to put inside one component. You want to have very fine grain components or you're okay with bigger components. The same with here in motion, right? You it's up to you to decide how big these steps should be. I'm being quite uh precise here. So, we have very small steps and there's no right or wrong with that. Okay?
But ultimately, if we have all these steps now, if we go back to the workbench, we can see now we have like a sequence of steps, right? Right? So this is a more realistic situation where you're processing things step by step and it gets kicked off by some API call. Right? Very common here on the back end. Right? So now if we want to kick this off, let's actually try it out. So vote in a particular poll. I do need an ID for that. Use the same ID as before. So here if I take a look in the polls state, I can see there is one with this ID. I want to vote in that poll. I can go to endpoints post to API endpoint here. So here we just have to the poll ID we want to vote for as well as the option ID that we're voting for. So these options it also have a ID. So let's say I'm voting for and I will add that right here and let's click submit. All right. So now you can see this takes a bit longer, right? Cuz we have some um we have some sleeping. You can see this is uh being shown to me in the tracing is running currently, right? So this is taking up almost 10 seconds because I'm manually adding some sleeping here. But you can imagine in the real world you would have a request response cycle to your database. You may want to make API calls to an AI model. Let's say these may also take quite a long time. And I'll actually have another video with MOSA soon in which we talk more about using AI in Moshia like making but there may be other reasons for why things take a bit longer. But you get great observability here out of the box as well. And so now if I go to states here and if I go to that particular poll we can see that the state has been updated here. And also I can go to logs here. We can see that there was a vote in this poll and it says vote received for particular poll which option was picked that one. And also in that final logger step we were also logging. So we still had some logs here from the starter app. You can always clear them out if you want. Okay.
So, we've seen API steps and event steps. There is one more important step that you need to know about which is the chron step. So very often you have some code that you want to run on a schedule, right? A chron job. Traditionally also very painful to set up but it comes out of the box here with Mosha. It's just another it's just another step, right? And but in this case, the type would be chron. And you can still give it a name and description. And we can specify how often it should run, right? So you can use the familiar syntax for that, right? So then this function will run whenever you specify it here with kron. Right? So what we may want to do is perhaps delete all polls that are older than an hour, let's say, right? So we could say something like to the user uh polls will only be available for an hour. Subscribe to the pro membership if you want. Right? Just as an example. Um, we have our polls here and we could say we could just do a quick check every so whatever you want to do here. Um, you can do you can just uh clean some things up very commonly. We can also delete things from state and I like to log that here as well. Right. So if I add this it's automatically picked up again by Mosha SS save. By the way, I don't need to refresh the workbench. It's automatic. It automatically picks it up. This chrome job actually already ran. Right? So it just ran and um yeah that's now also included here. You get it out of the box. very easy way to add chrome jobs and actually it was logging as well. Yeah. So you can see it's logging here as well.
Now about the state if this is not the perfect use case for state then what why should we use state? Well Mosha describes it in the docs. Actually there are some good use cases and probably things you don't want to do. So if you have persistent user data which is kind of what we have here right? So these polls we pro this probably belongs to some user. This is we want to persist it. We don't want to suddenly lose it. So we want to persist it in an actual proper database. Right? If you have users that are uploading files, let's say, we probably also don't want to use Mosha state. Or if you want to do something with real-time updates, as I'll show you in a second, we're going to use Mosha streams to stream the vote updates to the to a client. We it comes out of the box. Actually, we do not need Mosha statement. Or if you have a massive data set, right? So you also run into issues with that. So then when should you use it? Well, um if you have just some quick temporary data, for example, if you want to share data between steps, right? So what we did here in some steps if we take a look at validating a vote here if we take a look at if we take a look at voting here right there's an incoming vote right and remember we have like four steps after that and all of them need to get access to the poll ID and the option right so we're passing that through this data object every time right so in this step we're passing along the poll ID then in the next step we have to pass it along as well right it's it reminds me a lot in React with prop drilling where you have to drill down with the data They are component by component. Typically something we want to avoid in react. We avoid it with the context API typically. Right? Now here in motion one thing you can do is just put this in state and then you can read from it whenever you want in some other state. Right? So if there are some steps that don't really need the data, they do not have to be concerned with passing along data and they they just don't do anything. And then other steps when and then the steps that come after that that do need data, they can just read it from state. Right? Same for the chron step for example. Right? the chron step and so on that are not technically connected like that can also still read from state in that another good use case is if you're building up a big result that gets built upon in multiple steps in that case it would also be kind of awkward to try to force it through a bunch of steps through events instead you may want to store it in state as well and and then read from there whenever you please also maybe some API response caching very quick and handy way to do some caching out of the box as well.
All right, so we've built out the motion back end application here and there is one more thing that I want to show you here as well which is actually streaming updates to a client. Right? So here we have like a little workflow here. There's an incoming vote and we do some processing on that in separate steps. Now a client may actually want to be updated on the stage of that workflow. For example, we want to see what's going on at which step we are currently at. So we may want to stream that. Now previously if you wanted to do that from your back end you had to do some setup with websockets or serverent events yourself. But we don't need to do that here with Mosha. It comes out of the box. is actually one of my favorite features. So I can actually change the folder structure here as well, right? So we can group the steps themselves into a steps folder. So let me just move that in there. And then we can have another folder in here. Let's say for the streams that we have cuz you could have multiple streams. But we are just going to do that for so we just call it stream.ts. And we just have a little bit of configuration here. So I'm going to give it a name and it should have a particular schema. So for example, we're going to stream back the stage to the client. Okay. So now we have set up the stream and there are two things we need to do. So the first thing I want to do is write to the stream. We do that from the motion app itself. So we can just write to the stream from each of those steps. So if we go to that initial vote step, this is the API endpoint that sort of kicks off the workflow. What we can do here is let's say um at this point we want to write to the stream. By the way, now when you save you can see that the stream is being registered here. So it automatically has picked it up. So now what we can do is we can go to that initial vote step. Right? So that's API step the in that receives the incoming data and we can write to the stream from this step. So we get another property here in the context object called streams and we can pull the stream that we're we want to write to out of there. So that's the pulse stream and we can set something basically writing something to the stream. We are basically passing along the workflow with whatever stage we are currently in. Right? So we're telling the client, hey, we just uh received it. And then in the next step, the validation step, we want to write as well. And again, it's coming from the context object. So you can do context dotstreams or you can uh dstructure it directly in here. We're just uh change, but we're just streaming the stage that we are in. In this step, we go to the applying the the vote. So here we can also say, hey, we're currently in the applying stage and then also in the results updated step, which is kind of the last step uh that we have. If we had one more step just for logging, we don't need to stream from there. So this could be the last step in in which we want to stream something to a client. So we've set up a stream and we're writing to it. So now it's up to a client to actually consume it.
So in this case, let's actually create a front end that can interact with the Moshia backend application. So how does that work? Well, you can use your favorite framework. Uh I'm going to use an XJ s here to create the front- end app. You can use tens start. I have another video with Moshia on tens start but there right so there are other frameworks that you can use okay so I spun up a very simple nextjs application um we just have a homepage we have that polls we have the individual poll page and we also have some serverside logic here because we need to make requests to motion right so so let me actually start running the app so we can see something on the page go into the next s folder here also mpm rundev so nextj by default actually runs on port 3000 as well so we may want to run the motion workbench on a different port. So here in the Mosha package.json, we can just run it on port 3001. Let's say uh let's do it for that one as well. Right. So now if I restart the MOSHA app, it should run on a different port. So there's no clash. So now we can see it's port 3001. If I open that up, we see our workbench. Right? So it's very easy to change that in case you want that. And let me actually restart the next S app here. So now on port 3000, we should see All right. So now we have both the apps running. And on port 3000, we now see our client, our UI. Uh before we discuss uh the streaming, right? So actually before we discuss the streaming, how do we even interact with the motion back end? Because remember we have an API endpoint create a poll, right? So now we want to be able to do that from the UI. How does that work? So here we have a simple form, right? So here we have some simple inputs here. We can just create a question. The user can add options. When the user clicks on submit, we are going to create a poll. We're going to submit this first to our own back end. So technically you could try making requests from the browser to your MOSHA app. Um, but you know they may be served on different domains likely so you may run into course errors. So typically you do want to go through your own back end first also for other safety reasons and then from your own server side make the request to the Mosha. So that's what we do first. We pass along the data to API Mosha polls. So here we have some so here in the API I have um I have Mosha/poll. So we are submitting the data API endpoint on our own next.js JS server side and ultimately we are sending off a request to the Mosha app. So I put the Mosha base URL in an environment variable. So in my case it's running on localhost 3001. And notice I also have a Mosha websocket URL. This is for streaming. We'll talk about it in a second. Um, so now if we take if we open up our workbench here and we have our tracing here. So now if I try to create a poll, we can say test and one and two. Let's say create poll. All right. All right. So, you can see I'm actually being redirected here in my front end client. And if I open up the workbench here, we see that there was indeed uh an request here for creating a poll, right? So, we can see that actually we should be able to see it in state as well. Uh polls here. So, we have a poll here with question of test and one and two, right? So, uh we are able to pass data to our Moshia back end app from our nextjs front end and again works with other clients. So, front end frameworks as well. So, let's actually create another one. But should we create AI images or AI video? Okay, so create poll. All right, so we're being redirected here on the front end. So now we are able to create a poll. But we have a bunch of other API endpoints as well. So for example, we have to list all the polls API endpoint. Um, if we that's what we use when we load the page. You can see we're listing all of the polls here. So on my next js server side here, we are getting all the polls, right? So here we're making just a fetch call to/poll. So we should be able to see that here in the workbench as well. here under tracing if I uh load the page here you can see there is list polls here with the tracing info and so we're able to list and we have an API [clears throat] endpoint here for an individual poll as well get poll right so if I go to this poll that we just created we're listing we're showing the information of the poll well it needs to come from somewhere and we're getting that from Mosha as well we have /poll ID and for that we also have this get API endpoint right so here we make that call cool but of course the user should be able to vote in a poll as well. So when the user clicks on let's say vote here, we are going to make an API call to our own back end first and from there we're going to submit a vote to the Mosha app. Right? So here I'm using the Mosha base URL again and remember voting or processing the vote it goes through different stages. Ideally we are updated here in the front end on those different stages especially if it takes longer. This is a great user experience. If it takes 5 to 10 seconds the user wants to get some feedback on what's happening on the back end. So if I'm going to vote for AI images, we can see now that there is an update here that we can see validating, right? So we're seeing the the stage that the vote processing is in and ultimately it should be finished and we get the actual final result here displayed as well. Right? So this is a really smooth experience that traditionally would be quite hard to create, but this is very easily done now with the streams here in Mosha. So we were already writing to the stream from the Mosha app. So to make this work here, we just need to consume it, right? So you have to wrap the part of the app that needs to get access to it with a provider. Uh here we're using a separate component for that. But you just need to use the motion stream provider. It's a different package to have a dedicated package for React applications. And you get a websocket URL out of the box, right? So let me actually show you variable. This one that I'm using here. And then in a react component, I can use use stream item to get the actual data. Right? So here I get the actual uh so stage in which the processing is taking place. I can use that to render the markup here in the component somewhere right? So I have like a status bar right so you can use that data to render the markup in the component that you want to display depending on well in our case the page in which the processing is right and the cool thing is if we do if we open this in some other window so somebody else is also on that poll page. So if this person here on the right side votes for AI videos, we're going to see the we will see the uh updates here streamed in for this user and ultimately when it's finished all the users that are watching this page should be updated here, right? So we just have to wait a bit and now we can see both windows here are updated. Right? So I think if you're creating some kind of live uh feature like this, maybe live comment section, this could be an approach. Mosha describes some of the use cases for streams. So if you want to stream some kind of AI response or just generally you have a chat application and or long processes right where you want to give the user updates on what's going on kind of live dashboard with metrics or not notifications or these collaborative tools right where you have multiple users working together in some way right?
So that's how we can build cutting edge applications with Mosha I highly recommend that you try it out for yourself I would recommend going to the documentation and here under quick start it is very well described how you can get a new Mosha project up and running. I recommend starting with the tutorial option and exploring the workbench a little bit, but it's actually very easy to pick up, but your AI coding agents will have a pretty easy way of helping you out as well. And make sure to give Mosha a star on GitHub as well. And if you want to get updates, you can subscribe on the up for the updates here as well. So, I hope you have a better idea now on what Mosha is and what you can do with it. Thank you for watching and I hope to see you in the next one. Bye.