About this talk
In this talk, Yoni presents a solution to the common issue of excessive boilerplate code in full-stack development. He emphasizes the need for a more efficient approach to managing CRUD operations and data validation between the front end and back end of applications. Yoni shares his experiences in modernizing legacy applications and introduces his open-source library, Remot, designed to streamline the development process by allowing models and validation rules to be declared in a single source of truth. Throughout a live coding session, he demonstrates building a full-stack to-do application using React and Node.js, showcasing features like real-time updates, pagination, filtering, and authorization. The session highlights the power of using Remot to reduce repetitive code and improve productivity for developers working with complex applications.
Full transcript
hey welcome to the dev days conference you are in Hall one languages and Frameworks with our speaker Yoni and the topic that he's going to bring us today is back into front end without the duct tape now can you imagine this almost everybody who's been doing some development knows the amount of duct tape that comes with it you know I I'm a net cop developer I use
visual studio and the amount of duct tape code which boilerplate code which keeps coming with it is so much and what I actually hate is when I want to change something I'm so afraid to get in there because if I change something I don't know what's going to happen and uh today Yoni has something to share with us and uh I'm actually very interested to understand how
the whole thing works so Yi the stage is yours thank you hi everybody let's start um I'll start by saying this is a live coding session I'll be running out of these slides in a few minutes and from there on it's all going to be me coding and you watching so so wish me luck and I hope you enjoy um few words about myself I spend most
of my time writing code um my focus has always been large complex Enterprise applications I've been doing I've been modernizing Legacy applications which usually have hundreds of database tables hundreds of business entities very complex um user interactions lots of crud lots of complex workflows so this is kind of my background um I'm both a lazy and an error prone developer which I I say to um make
it to make you understand that I need a lot of tools to help me languages and tools that I both take and create for myself that have helped me work less write less code and avoid errors but when I say less code I don't mean any low code tools or anything like that I love code I code all the time and I just need tools to help
me write less um I always prioritize getting features into the hands of users over uh beautiful architecture or bleeding edge tool so that's something else you want to know about me this is an image of my I would say best project to date and this is a little bit by myself so how I build applications is really traditional and simple I like keeping things simple nine out
of 10 times it's going to be as simple as a single page application you know using any framework you can imagine like react angular view Etc uh an API server usually no. JS and um that server interacts directly with a relational database so most most of the times no complex micr service architectures just a simple monolith that does the work I really like it keeping it simple
so I made a kind of a short list of the main features that I find in almost every Crow application my applications that do a lot of crud if I split it between my no JS API server and my front end it starts with model types we need model types to uh you know move data around in our server but we also need those model Types on
the front end and to interact with our UI widgets we need CR API routes you you get put post delete to do all those interactions with your API server and we also need to call those API routes from the front end each and every one probably we need data validation on the backend because we can't accept any unverified validated data into our database but we also need
data validation on the front end to get our user users experience better and you know enjoy the power of the browser and making validations before we even call the API the API server we obviously need access control because not every user is allowed to perform in every action some are limited and we have to protect our API in our database but what's interesting is a lot of
the times we also need these rules to be reflected in our users screens and interfaces because if they're not allowed to perform an operation this is usually this usually means they can't either you know see a button or use a button or it's disabled so there authorization cues on the front end as well and then there are other things going around in your back end such as
SQL calls they using an omm paging storting and filtering is almost always necessary uh real time is sometimes uh required in a nice Edition and on the front end you'll have your routes and your components and looking at this short list I it's easy to see there are things in the front end and the API server which are basically a reflection of one another right we like
to talk about a plug in a socket because if we change the model type model Types on the back end this usually reflects a change in model Types on the front end as well as these API calls and routes that we build on the back end and that can cause us a lot of mistakes and errors if we change one and not the other so these are
kind of reflecting one another same grow for for data validation and access control and on the back end we sometime we see a lot of comp ative and boilerplate code we were talking about that um you know writing those same API routes basically doing the same for one business entity or database table or another and then you have your orm Risco SQL calls paging storting and filtering
all of these tend to repeat and boiler plat code is something that I really hate having and seeing and maintaining especially maintaining because then I want to change something and I have to go all over my code and look for what to change um some Modern full stack framewor Frameworks are starting to work on at least some part of this code duplication if we're looking at model
types and cred API routes then we've been seeing a lot of advances in Frameworks uh this is these are Frameworks in the react World obviously there are others for other for other frontend Frameworks but if you look at nextjs what they're doing today if you look at remix they're making API calls and consuming those API a lot more holistic um and also sharing of model types between
front end and back end if you look at Redwood JS which does that with graphql or trpc T3 all are very interesting Frameworks and tools that I recommend you take a look at which make this whole thing more um you know easier to work with faster to develop and less you know it causes less bugs and errors but for me as I develop I like to think
of this whole thing I like to think in in a level that every single part of of uh this list can be derived from a single source of truth if I look at a business entity I can I want to imagine or an Invision a way in which this this entity can declaratively State all these things such as what is the model type what are the validations
for the fields what's the access control rules and have that affect my entire without writing a lot of repetitive border Place code and so to make our lives easier as developers I teamed up with a lifelong friend friend and colleague and we created remote which is an open-source MIT licensed library that covers exactly this uh thing that I was talking about I'm going to use remot in
this session to demonstrate all these principles but you can apply the same Concepts to your code with any other libraries or that you're using okay so what's this live coding session is going to be we're going to take a react to-do app really simple one front end only with no backend and then we're going to create turn it into a full stack app with all of these
elements that I've just listed an OJs server end to end type safe Crow API server side paging so filtering real-time life queries validations that your right once and affect both your front end and your back end integrating a post that post database and authentication authorization I think I have about 30 minutes to try to do all that let's see if I can do so this is our
react app let's see pretty simple uh it uses vit for tooling which I love and is very fast and efficient and it has and let's you know first let's start by spinning up this U this app all right npn run Dev and V's going to start my app and I'm going to open it right here and you can see the the to-dos and this is all just
one single react component let's have a look at it there it is we just close a few things this is our app component this is the entire app you're seeing on the right um the task list is defined here as the react state uh a tasks um array the new task title is this area what needs to be done uh we've got a function to add a
new task which basically creates a new task object based on the new task title sets some default values and adds that to the task array uh and sets the new task title back to a blank string we have the set completed function used used by this checkbox here that basically creates an updated task and and um changes that in the array to have to reflect the the
new state of the task delete task if I just one and I delete it using this x so delete task just remove the tasks from the array and set all completed and uncompleted is just reversing the array and changing the state very simple react app frontend only I don't think I'm not sure if I need to even go over the the rendering part but basically we've got
a form for the adding the new task this iterates the tasks and create this list and here are the set all completed and set all uncompleted buttons right so we've got our front end only app doesn't do anything interesting let's move on let's create a backend for app so I'm going to start by creating a backend folder with an index TS file express I'm going to use
Express in my backend server is theine Express perfect okay now normally uh okay let's just write one uh get um route just to see that this is all working it's gonna wait it's gonna res send by Dev days perfect this is our route and usually we're going to have usually we'll have uh the app. list in here but I'm not going to do that I'm going to
do a nice trick I'm going to use vev server to serve this Express back end I'm going to use a a plugin I'll just show express this plug in let's see how it works and basically I tell it where the source from my back end is and it's going to use this to um run my Express I'm going to export app and this is going to run
my Express app with vit let's see if it works hopefully it works great hi there so we got we've got an Express back end running V is going to run it and hot reload it as we make changes to the back end and um let's so let's okay what the first thing I'm going to do is um oh I just I forgot to mention this uh task
list uses a type for a task let's go and look at that type it's a simple typescript class as an ID a title A completed which is a Boolean and a created a date so I'm uh uh task class also for my back end and let's see how I do that first let's just move it to a shared folder let's create a Shar shared folder it's going
to be shared between the front and the back end move that here hopefully everything will still work let's go back still works and what I'm going to do is going to expose an API using this uh task class let's see how I'm going to do that I'm going to decorate this class with decorators from remote that's the important part so the first decorator tells this class this
is an entity a business entity and it's going to have its own database table as well I'm going to um I have to say that it's allowed that crud is allowed on this entity and I have to Define these fields so let's s right let's do fields [Music] so the ID is going to be a CU ID the title is going to be a string the completed
is going to be a ban field and the created at is going to be a created ad field perfect okay so I I added some code to this task to tell remote how to expose it as an API and now I have to do is go back to my index TS and Imports Express and add that to my Express backend it's a little bit of work but
there we go and then I have to expose the entities so there's an entities array here I add my task to this and let's see what happens so right now I already have I'm supposed to have a API test which returns an empty array fine great that works so I already have this API route that returns an empty array of tasks because I don't have any tasks
in my back end database now let's let's test this um reest this is a this is a thunder client the kind of like Postman like um thing that I use Let's uh post a task into our back end let's say it's title as test and send and as you see that the API that we've used the get here the post is also working created a task for
us on the back end with an ID a Cy the title and the rest of the uh default values so also the post is working so we have that data now in our database now you're probably asking where is the database because we haven't defined any database well remot uses a a default Json based database it's just stored in this folder called DB it has a task
Json file which has our task in it this is this is the default Behavior but once we add in in you know in a few minutes we'll have We'll add post and we have a have a decent database this is just it's nice for prototyping and it's nice for playing around so now we have let's go back we have our setup and we have our entity and
the API is okay now what I'm going to do is I'm going to grab all these just hide this let's grab all these tasks and just post them into our back end so we have more data in our back end and remove them from here on once I remove those the the the to-do list is going to be empty because I removed it from the react State
and let's just post it here into our backend database okay there you go Json send great so now we have all these tasks in our back end and you can also see them in this Json file perfect now we have to return these to our front end okay so let's go to our app and we're going to add a task repo object which is going to be
repo of type task this repo object is or is used by remot to interact with our backend API and with our back and eventually with our database from the front end it's going to help us create all the crud functionality we need for this to-do app so let's start by fetch fetching the tasks we're going to use use effect from and we're going to tell it like
we're going to say passo find then right then set tasks once we do that and once I save it we're going to get all our tasks back from the backend API let me show you the network tab okay again this is going to run a get a get request from our from the rest API we've just exposed using remou here by by adding the task to the
entities array fetching the data from our backend database and in to our react State now this find is very naive just returns all the tasks but if we want to let's say I don't know um filter let's let's start by U um you know PES let's set a limit to two we're only going to see two tasks and let's set a limit to three it's only going
going to return three time this is at the API level so this is backend uh paging let's go for the second page page two we get the second page and Page Three we get the third page so we've got our we've got our end points not just returning data but also performing backend um uh paging for us now let's try to uh filter the data let's add
aware and let's say completed uh false true once I do that all I get back from the API is is the completed tasks and again a simple API get call with a completed parameter um now this is also important that this is type safe because again we're using the task uh the task entity here which is defined as a Boolean so typescript saves us from doing something
like this and throws an error if we try to use a string here so this is end to end crud safe let's try false sorry false we get all those that are not completed and we've shown where and let's try uh order by so you can order by um let's see create at uh sending or descending again simple rest API calls returning data sorted from the backend
database zero boiler plate to get all of working okay so let's say let's see what have let's order it back like we want to we've done setup we've done entities we've done paging storting and filtering let's complete the rest of the crowd operations to this whole app little app is going to work um first let's let's do it just one by one adding a task is a
simple as calling task rep. insert and sending it the object of this new task okay let's remove unnecessary things because the back end will give us the these uh by default set do tasks awake of course and now when I add a new task it's going to be added to my backend database to prove that I'll go to the backend database and see my test one right
here perfect um let's do the rest let's do the set completed which is the checkbox all I have to do again use the task repo call await task repo do save with that same modified object and oh I forgot to show that this this was a the the created task was just a post request okay a successful post request with the Json data something you you would
see in probably just any regular rest API and the same goes for the updating of the completed State you're going to see a put request like you see here with the ID of the task being modified and it's and once I change it you can see it kind of live here online once I Chang it the values you can see the values changing in my backend pseudo
database moving on uh delete task you guessed it it's pretty simple PR task. delete also going to be working let's delete one it's deleting perfect refresh delete it on the back end and let's wrap this up and and where the I want to show the delete delete action let's add add one and delete it you can see the delete um request coming in so we've completed CRA
but we want to do more because now we have such a nice uh looking to-do app but it's very static because it uses only rest end points so if I duplicate it and let's say I change something here then the other user do does not see that change reflected obviously until he or she refreshes the page and let's change that and change into something more interactive so
with REM is pretty simple all I have to do instead of using task reple fine to load the task at the beginning I'm going to use live query and instead of then I'm going to use subscribe which gets an object that I can use to apply changes to apply changes to the current react State that's all I have to do once I do that let's kind of
put it side by side and we can see that the changes are reflected in real time because now it's using server sent events you can you can still see the put request because we're still using rest to perform the the mutations but on the other side all you're going to see is um server sent events causing the modification of the of the react state in the live
so just change to s a single line of code again by using this entity as a single source of Truth this becomes really easy to perform something that would probably require a lot of boiler plate code to do without remote so let's see we've done setup entities paging cred operations and live query next thing I want to talk about is validation something I'm very I'm very interested
in because let's say we want let's let's go back to our task which is where our again I would like most of my business logic and validation rules and all my rules to be defined here so let's try um setting this title field to be required validators required okay once I do that if I try to add a task without uh without giving it a title I'm
going to get an error should not be empty but let's look at the I'm not seeing any network calls being made because this validation happens in the front end it's not even calling the back but if I do if I if I use the API directly let's use the API remember okay let's go to API task and try to post an task we're going to get the
same error from our back end because the back end is using the task class as well so it has the validators required in it as well and these this is just a built-in validator this can be any error function I can make this if I just give it the generic type I can get a task here and say if task title links under throw to short wa
just arrange this okay once I do that I get the two short error here and I would also get the two short error here but if I add a task which is long enough then it's going to work so the important thing here with validation is you write it once and you get it both in the front end and the back end and again it's completely code
based not some no code or low code tool you can write whatever you want here you can write logic here that depends on whether it's running on back end or the front end different logic and get very interesting and these things happening how am I with time fine um okay next thing I want to show you is operation the set all completed okay let's say I want
to use you know my user asked me to implement this set all completed call the back end set all the tasks as completed or not completed according to the parameter and let's try to make that work with so I'm going to do I'm going to do just iterate the tasks of await task find and I'm going to I'm going to task repo update uh so T go
save with this task and complete it okay very we go so this is going to work it's updating all the tasks are being completed I refresh the back end it's all reflected in the back end but let's see what's happening here there are lots of put requests being made here so you know the user is happy I might be happy but my boss might not be happy
because I'm making too many put requests and you know can imagine if there were hundreds of tests in this list so this is not very good idea in terms of performance but why why I'm saying this and why I'm showing you this because with REM I can actually run the same logic as backend code and then call it directly from the front end in a really simple
manner so let's do that let's add up let's add a tasks controller okay and in the this T controller I'm going to just copy and paste this code okay I'm going to adjust it a little bit it's going to be a static function okay it's got It's got to have as task repo and the same way I wrote the front end code back come is going to
be the same it's going to be a repo task I don't need this because this is the react code I've got a static function that does the same thing and I'm going to use it on the back end now how am I going to am I going to tell REM if this is a back end function I'm going to use a decorator it's called backend method I'm
going to set this allow to true and I'm going to register this tasks controller just like I registered the task in my index TS going be controllers task control perfect and now I'm going to go back to TSX and I'm going to tell this set all completed function to call directly the test contr the test controller wait test controller set all right set all completed completed and
remove this okay so I've done a little bit of work but when I got here now is that once I call the set all completed I get just one post request to the back end with the complet with the completed state which does the work on the back end and the interesting thing here is that I've used exactly the same code that I was using on the
front end to call the database when I was in the front end this iteration caused rest API calls when I'm using this as backhand code it simply calls the database directly so here it's using the Json database we'll soon have post with with SQL statements going to to post but it's going to be the same syntax doing something different behind the scenes but look how easy it
was to just refactor code from front end to back end that's the thing I was I wanted to show you so let's see what we've covered crd live validation of leading multiple tasks let's at a real database it's time we've used a nice little Json database for prototyping and now we want to move postgress you can imagine this is going to be really really simple I'm going
to again REM REM post scripts I'm going to import a create postest data provider function and I'm going to set the data provider to that and give it a connection string which I prepared in advance just that quotes this is my connection string to my post database and look all the tasks are gone they're gone why because the the database is empty but what you can see
is O sorry what you can see in the terminal here is that when when I refreshed and when I saved and and was reloaded by V remount went ahead and created a database table called tasks for me if I look at my post I can see here let's refresh I can see the tasks table was created for me but it is still empty now let's go back
to thunder Cline and hopefully I can find my tasks because yeah probably lost lost all my test my tasks wait let me get them from somewhere else no I lost my tasks well I'll just write them so we've done a lot of things we have database we've just done that let just REM this and our next thing is going to be off we'll do that soon and
the rest will we'll be showing you some examples so yeah I I lost my list of tasks but now I have a a new one and uh We've added a database you've seen it was just one line of code the connection string for postest and now this is using post let's prove it let's go to again post press and see that the data is there if I
select the top 1000 I get the task that I've just added so post is working now we're not just using a prototyping Json database SI okay last thing I wanted to show is off because this is all very nice and you know not related to the real world because in the real world not every user and everyone who has access to my API can just grab all
these tasks and do whatever they want this has to be restricted so let's say I restrict this and I tell the reme that I want only authenticated users only authenticated users to have any access to this API at all once I do that I get a forbidden error from my uh from the the API that fetches the task okay it's not allowed anymore I have to do
something to change that so let's go ahead and just um okay just I want to say before that remot is completely unopinionated when it comes to your off uh framework provider or any tool you're using to authenticate users okay that's not remote's concerned we're concerned with crud only but um you know we we've used uh tools like next off or like um various uh tools that Express
have and everything works with remonster it's not a problem let me just show you a quick example of how I can add off to this app pretty quickly let's go back to the DS I'm going to cheat a little bit here and use a snippet okay but I'll go over what what I've done uh I'm going to move this sorry move this up where am I G
to move this up okay so I've used cookie session which is an Express package which is a really naive uh session management using cookies uh it's pretty simple you just set it up you send a secret and it just works okay so I've added that and I've added a list of a very very naive user database obviously in a real world this is going to be saved
in some data store or provider but these are just J andd which are going to be my users for this example I've added a signing route and you see this is a regular express route has nothing to do with remot um just goes to show that remot is a library you can use with any other uh way of development you wish so I have this post for
sign in all it does is finds the user in the valid users list adds it to the session which then adds it to the cookie and sends it back to the to the front end a sign out which basically nullifies the user and a and a current user these are the three API routes I added to do this very naive and basic off Solution on the front
end what I'm going to do is cheat a little more go to my main TSX for my react app and change this into a a uh component that I prepared in advance but it's really simple one it just as the name you write Stever Jane and it gets you signed in it's just to show you what's uh you know it's it's a really simple simplistic uh example
let's say I write Steve I'm signed in I still can't see the tasks why is that because I have not connected an integrated remote with this whole off system that I just repaired so let's go nxs just going to close a few things here and all I have to do is tell remot here that how how do you get the user to get the user you get
a request object and you extract the session Rec session user from this request that's it and I'm back to work and I and I see the tasks so the integration between remot and a very a very naive cookie session off system works with just a single line of code and not a lot of boiler plates so got this out of the way I wanted to show you
something just one more thing about um off it's not it's not just about being authenticated or not let's add uh roles let's say that insert is allowed only if you have the admin R and also also delete uh allow API delete only for admins okay so now if Steve wants to add a task it's forbidden okay and also deleting the task is also forbidden and let's say
that um our user Jane is does have the role of ad okay so once we sign out of Steve and sign to Jane Jane is able to add new tasks okay this is true for you know for the backend um API that we've used now we we have an a system with roles which is fine but what's even more important and I discussed it a little bit
in the beginning is we have a problem with Steve because Steve is signed in it he can't um add new test but he does see this form and also this x button which you can't use so let's go to our front end and prevent that again a really simple way we're going to take this form and we're going to condition it based on our task repo again
our single object for everything metadata API insert allowed okay so once I do that Steve could no longer even see the form for insg tasks but if I come in as Jane I can see it I can do the same for the task let's just do it really quickly task metadata API delete s right API flout right so now again Jan can see sign out sign in
as Steve Steve can't see the x button so this is how an off rule defined at the entity level can affect a single rule defined here and this is this can also be Arrow function okay I'm just using basic stuff but it can be error functions you can write whatever you want here but this both affects the front end and the back end in a single source
of truth that was what I was uh trying to show you um let's see how we are with time you have some more well first of all you know let me go back to the slides and then maybe I'll show you something else so this was the this was the demo I have a few minor things to show maybe I have time I'll show them if not
someone will stop me uh REM F fits in your stack I've shown react with an Express back end we've used it with angular and the fastify back end we've used it with various meta Frameworks such as nextjs KN vkit um solid start you name it and if we don't support support it you know open an issue or use our Discord and we'll just support it really quickly
it also supports nearly every uh database you can think of uh obviously the the common ones like my SQL post andite but also mongodb SQL Server even Oracle and other and others and it can run on any node bun or Doo um server uh there are some features that I wasn't able to show you in this short demo but um obviously you can you can find you
can look and find maybe I'll show you the the Swagger part if we have a few more minutes uh but database migrations which I don't really like I like the the sync uh feature I showed you where you just add an entity and and remote checks if that if that exists in the database and if not it adds necessary tables and columns but you can use migrations
like you're used to in other or such as Prisma um graph que and open API entity life cycle hooks remote is very customizable in the way you can affect everything that's happening uh whether it's changing things before the that goes into the database or after having various Hooks and effects sending emails or text messages or whatever you wish uh it's completely supports relations it's it's not something
you can show in this kind of simplistic demo but the relation relation acquiring part is very impressive which you should try it um things like backand only updatable Fields like things you can't update from the API but there uh computed Fields if you don't like decorators some people don't like them uh you can complet use remote without any decorators at all you can even use it with
plain JS and JS Doc and um this is the the remote website where you can find tutorials and guides on the things that I've just shown you now again these constructs are something you can use with any with other Frameworks you're using just you know think in this in this mindset but uh if you want to use room it's completely there free for you for us and
for you to use this is our Twitter handle uh we do have tutorials for uh really tutorials take you you know through the entire journey of this to-do app even further with more features it's like an hour and you can be you know deployed in production with a nice little app with remote um if I do have some more time I think I right okay I just
want to show you one little thing back to the code sor um let's show you how easy it is to create and a really simple admin UI with ring all you do is set admin to true and we get something like this okay this is just kind of a generic admin with your your database your your entities nice diagram which is useless when you have just one
entity uh you can edit data right here change it save it's nice to have something even just for development use you can really go into if you have any relations you'll be able to see relational data here you can delete and is paging and whatnot and this just comes out of adding this admin true and you get this working if you want uh if you like Swagger
let's do a quick demo of swagger three lines of code I have to H just one more thing I have to extract this here into this API variable and I have Swagger let's go API dots here's my Swagger of this API I just created here's the get request for the tasks with all the possibilities for paging limiting and and and filtering and whatnot and it just works
so it's really nice if you like graphql trust me it's another two lines of code and you get a complete graph Vi about client working here all of these are really easy when you use that concept of having an entity as a single source of Truth defining all your rules here obviously the you know like the admin screen I just showed you reflects all those rules if
I'm signed in with a user who can't delete the delete will not work even in the admin so this is very powerful put a put as much logic I think as you can into the business entity and have it affect your entire um well I guess this is what I wanted to show so thank you and if you have any questions guess that'll be a good time
questions hey thank you so much y you know what you know I've been developing all my life with asp.net when I look at this I think that my next project I need to take remot for a spin it looks like a lot of fun and it was so nice to see you with so much energy going through all this stuff um and just you know throwing in
an admin with one line throwing in Swagger with a line it's it looks like you know it was fun let the boiler plate not bother us from doing the real the stuff that is important right that's right that's right great I'm going to say thank you I I think our time is up we I already see moderator dropping in and I'm assuming we'll have questions hitting you
from different directions later during the conference so I'm going to say thank you thank you so much bye bye
More from this event
See all 73 talks →
Tomas Lekavicius: Building Tech Product Offer
42:08
Alisa Dammer: Science and Tech Backed Approach to Increase Productivity
44:53
Roy Wasse: The Definitive Answer to Measuring Developer Productivity
44:47
Pierluigi Meloni: You’re a Great Coder? That Alone Won’t Get You Far
44:47