00:00in this video we'll do a full course on
00:02accent an awesome web framework for rest
00:05we will explore three main sections the
00:08beginner section covers the hello world
00:10quick Dev setup and the static routing
00:13in the intermediate section we will do
00:15our first post API for login we will add
00:18cookies and recipe eyes with our crud
00:21mock model layer and in the advanced
00:24section we will Implement our first
00:25Custom middleware Custom extractor and
00:28Implement our custom error handling and
00:30request logging everything is marked as
00:33a YouTube chapters below and now best of
00:35all we are going to have a quick Dev
00:37environment with our server terminal on
00:40the right our quick Dev client terminal
00:42on the left and when we press refresh
00:44we'll see our request flow on the back
00:47end and the client response with our
00:50headers cookies and response body OK
00:52let's get cutting so first we have our
00:55talk show main to be able to have our
00:57async and then we're going to bring our
00:59cargo to mail and the first thing we're
01:01going to do is we're going to add axum
01:03make sure to add the latest version and
01:06now we're going to create our first
01:07router which is going to be our routes
01:10for hello it's going to be the router
01:12for maxim and then we are going to
01:13create our first route with the path
01:16hello and then it's going to be an HTTP
01:19get so we're going to use the routing
01:21get function which is taking a nesting
01:24function or a closure with a nothing
01:27block which is what we are doing right
01:29now and we're going to return our HTML
01:31content hello world now we make sure to
01:34import HTML which is an XM response type
01:37we're going to close the import to make
01:39some space and now we can start our
01:43server the rod Server doesn't have all
01:45the types yet but that is going to get
01:47solved when we are going to configure
01:49our server now we're going to create our
01:51address which is just going to be a
01:53standard socket address from the standby
01:55library and that will be from Texas
01:58topple with our IP address as an array
02:01and a pot number then we are going to do
02:03our debug print and then we're going to
02:06start our server we're going to bind it
02:08with the address that we had just above
02:10and now we're going to call serve with
02:13our router and we're going to do into
02:16make service so that is a way that we
02:19save a router and we are going to see
02:21later how we can compose routers that is
02:24a sync so we're going to do an await and
02:27then we're going to do an unwrap and
02:28that would be the onion wrap that we're
02:30going to do besides the mutex ones and
02:32now we can bring our terminal and we can
02:35do our cargo run that will start our
02:37server and if you open your localhost on
02:41the 8080 hello in a browser you will get
02:43your hello world well formatted okay so
02:46that's pretty cool so what we have done
02:48so far is we have call Rod on our router
02:52which take a path and a method router
02:55that will return a router object into
02:59our Woods hello variable and then to
03:02serve this router we are calling the
03:04into make service which is going to take
03:07the router and make it as something that
03:09can get served by the server now if you
03:11want to learn well you need to iterate
03:13fast and so what we don't want to always
03:16open the browser to check what we have
03:18so one thing that I like to do for my
03:20quick Dev is I like to have the client
03:23in the cargo test and you could also use
03:26cargo examples as well but for now we're
03:28going to create a quick Dev in our test
03:30folder and now if we bring our cargo to
03:33ml in our Dev dependencies we are going
03:36to add a httpc test and that is actually
03:39a little libraries that I did to do very
03:41convenient HTTP client testing and
03:44printing of the result so we're going to
03:46use that and now in our quick Dev we're
03:48going to have our Tokyo test to make
03:50sure that we can have our test as async
03:53we're going to create our HTTP client
03:55with our base URL which is going to be
03:58the localhost on 80 and we're going to
04:01do our first do get on hello and that is
04:06async so to execute it we're going to do
04:08a weight and then we're going to print
04:09it and the print is async as well so
04:12we're going to do a weight so now that
04:14we have that we're going to bring our
04:16back end terminal from the right and
04:19we're going to do a cargo watch Dash
04:22quiet Dash clear in between each
04:24recompile and then we're going to watch
04:27only the source folder because that is
04:30going to be for our backend and then we
04:32are going to execute run so every time
04:34we are going to change a source code is
04:37going to recompile it and run it again
04:40that is our server and now on the client
04:43side we're going to have another
04:44terminal usually in vs code I have them
04:47side by side and we're going to do a
04:49cargo watch quiet clear watch and this
04:53time we are just going to watch the test
04:55folder and if you use examples you will
04:58watch the example folder obviously and
05:00then we are going to execute and that
05:02would be our cargo test quiet only the
05:05quick Dev and then we make sure that we
05:07have no capture such as we see the print
05:10line in the console and now when we are
05:12going to press enter is going to do so
05:15do get on hello and we have our very
05:18clean response print which is the get
05:20hello with the status the headers and
05:24the response body and then later we will
05:26even see cookies if we had set cookie we
05:29will see the cookies over there okay so
05:31that's pretty cool let's go back to our
05:33main.rs and typically when you return
05:37some response you wouldn't really do it
05:40in a closure but you will do it in an
05:42async function a Handler function and
05:45usually to do that we're going to create
05:47a little Handler hello section and a
05:50Handler function is just an async
05:52function that return an implementation
05:55of into response which is an accent type
05:58we are going to do our debug print it
06:00and we're going to do some alignment
06:02later that is going to be very useful
06:04and then we're just returning what we
06:06returned before and now if we bring our
06:08Terminals and we press save on the quick
06:10Dev we see that in the quick Dev
06:12terminal we have our hello request and
06:16then in the back end terminal we have
06:18our debug print with a Handler hello so
06:20that's pretty cool so now what if we
06:23wanted to pass a parameter to this URL
06:25such as we can say hello and the name of
06:28the user so the way it works with XM is
06:31you will create a struct for example
06:33hello params we are going to say name
06:36and we're going to make it optional this
06:39is going to be an option of string and
06:40then we're going to derive it for the
06:43Box just for us and then the important
06:45point is to make it also derived from DC
06:48allies from set a so for that we're
06:50going to bring our cargo to ml and we're
06:53going to include the seti dependencies
06:55we're also going to include set a Json
06:58for later so now we can import short
07:00said this allies and now in our Handler
07:03hello function we can do our params and
07:07here's a trick is we do a query which is
07:09an axum extractor and we're going to
07:12learn more about that and that will
07:14allow us to extract the query parameters
07:16into our function and now it takes one
07:18type which is going to be our hello
07:20params so the extractor here is a double
07:23struct so what we can do is destructure
07:26the params directly into our query type
07:30such as param is just our hello params
07:33now we can print it in the debug if we
07:35want and now we can extract the name out
07:38of it and default it to world if there
07:41is no name and to do that we're going to
07:43have params which is our Hello params
07:45type name which is obviously our option
07:48of string and now we're going to do as
07:50deref and that will give us option of
07:54reference of string and that will allow
07:57us to do unwrap or wall static string so
08:02this way we don't have any new
08:04allocation and now that we had that we
08:06can format it this way where we do the
08:09braces name and obviously we put that
08:12into a format macro now if we press save
08:15it's going to restart our server and if
08:17we bring our quick Dev code and then
08:20we're going to change our do get to be
08:23on hello question mark name equal then
08:26we bring our quick Dev terminal press
08:29save and and voila we have our question
08:32mark name equal gen and we have our
08:36so pretty cool and by the way big thanks
08:39to Krab nebula for sponsoring this video
08:41and also I'm trying to go full time on
08:43the Ross Educational content so feel
08:46free to visit my patreon page any help
08:48is a big help okay back to cutting
08:52so what we did here for hello hello is
08:55that we have the argument of the
08:57function mapping to the URL query
09:00parameters so that is what the query
09:02extractors allows us to do but what if
09:04we wanted to have for example a route
09:07Halo 2 where the value will be in the
09:10path and not as a query parameter so
09:13we'll do hello to mic so for that we are
09:16going to build our Handler which is
09:18going to be a nothing function Handler
09:20header 2 it's going to return the
09:23implementation of into response and then
09:25as a function argument we're going to
09:27have our name and now we're going to use
09:29a path instructor from axum and we're
09:33going to give the type and then we're
09:34going to see how we map that above in
09:36our router and pass is it upper struct
09:39as well so we can destructure it
09:40directly in the function argument so now
09:43that we have that we can just paste very
09:45similar code and above but now with a
09:48name variable now if we scroll back up
09:51we are going to do in our water we can
09:53add another route which is going to be
09:55route Halo 2 and the trick here is we're
09:58going to do a slash and then cut on a
10:02name and so that is what Taylor's accent
10:04where to extract the data from for the
10:06past and the mapping is by order it's
10:09not by name and then we're going to give
10:11our get Handler hello to and that's it
10:15now we can bring our quick Dev code and
10:17terminal and we are going to change
10:20hello to hello to mic I'm going to press
10:25and that's it we have a Halo to make
10:27with our strong mic over there so that
10:30is pretty cool so now we are ready to
10:32build our static routing but before that
10:35we are going to use a cool feature of
10:37axum which is composition of routers and
10:40for that let's rename our section what's
10:43hello and we are going to have a
10:46function very simple function which is
10:47going to be round hello which will
10:49return the router I'm going to copy
10:51paste what we had above and now on top
10:55we are going to do our router new but
10:58dot merge the right Halo and that is
11:01allowing us to compose multiple routers
11:04together and now our rat hello is not
11:07really a Rod's hello anymore but it's
11:08going to be rut or because we will
11:10compose different routers into this one
11:13and we have everything much more
11:15componentized now okay so now let's
11:17Implement our static routing so it's
11:19going to be raw static that will be the
11:21naming commission we are going to follow
11:22and will return the router we create a
11:25new router and now because it's a static
11:29fire routing we want to have a nested
11:31path so we're going to call Nest service
11:33which is going to allow us to give the
11:36root of the UI errors that we want to
11:37take it from so we're going to map it to
11:40the root of the domain name and then
11:42we're going to use a pre-built service
11:45to serve the directory and that is going
11:48to be a get service for maxim and the
11:50service to do that will be a serve dear
11:52and you give the local path
11:55now axum is very well componentized so
11:57serveda is not part of the axum core
12:00library but axum use Tower as a service
12:03Library so the way it works is if we
12:06bring our cargo to ml we're going to
12:10tower.htp and we're making sure to
12:13import the features FS for file system
12:15so once we have that then we can import
12:18the tower HTTP served here and so that
12:22is one of the things very well done in
12:24exam is reser2 have his own service
12:26infrastructure apis it used Towers to do
12:29this kind of things and then you can
12:31piggyback on the tower ecosystem
12:34so now we're going to go back to our
12:36route all and reset to merge it because
12:39accent makes sure that we cannot have
12:42overlap of URL and so since we are
12:44nesting from slash that will overlap
12:47with our hello but usually static
12:50routing you will do it as a fallback so
12:52what we can do is fall back so service
12:55and we give our Watts static and so if
12:59it doesn't find it in the route above in
13:01all of the mergers then it will go to
13:03the fallback service so now if we go to
13:06our quick Dev we are going to do a do
13:09get on Source slash main.rs obviously
13:13you will point that to a web folder
13:15somewhere but for now that will do it
13:17then we do our way print and await and
13:20now if you press save we get our hello
13:22to make then if we scroll down we get
13:25our source main with the content and
13:28even the right content type which has
13:30been set by our served here that is
13:34so let's delete that we're not going to
13:37and now we are ready to do our first
13:39login API and for this the first thing
13:42that we're going to do is create our
13:44error module for when the login fail so
13:47we create our module so we get into the
13:49our module and then we're going to do a
13:51pub NM error and so for this example
13:54code here everything will be in this
13:56error eventually you might want to split
13:58it in different layers and for now we're
14:01just going to have our login file error
14:03we're going to make it debug and the
14:05best practice that I like to do is to
14:07export a type Alias of result on top of
14:11this error type and then I will
14:13re-export result and error in the parent
14:15module such as I always have a pair of
14:18matching of error and result so that
14:20allows me to normalize everything pretty
14:22neatly but obviously this is just a
14:24personal preference so do what works for
14:26you now the important things from an
14:28axon standpoint is that we need to
14:31implement into response which is a trait
14:34of axon for error and that is really a
14:37key trade 8 in exam and then the
14:40animation does need to be implemented is
14:43going to be into response it's going to
14:44consume itself and it's going to return
14:47a response which is an accent type and
14:50that is going to become very critical
14:52later but for now we're just going to do
14:55a debug print and then we are going to
14:58return a temporary error for now which
15:01is going to be internal server and then
15:04we're going to say unhandled client
15:06error and axon has from this topper into
15:09response we're going to make that much
15:11more advanced later but the key here
15:14which is very important from the start
15:16is to never ever pass through your
15:19server error to the client because that
15:22is a big security exposure that you
15:24don't have to take so in security is
15:27very important to have the lazy path
15:28being the safe path so by default if we
15:31don't do textual work we don't send
15:34extra information to the client later
15:36we're going to see how we can have best
15:38of both world where the server will have
15:41all the information and we can cherry
15:43pick what we want to send to the client
15:45but for now this simple solution will
15:47work very well now if we go back to our
15:50main.rs I'm going to re-export and that
15:53is just my best practice for now from
15:56this module error the error and the
15:59result so like this I have create error
16:01and create result that I can Import in
16:04other modules and if some modules have
16:07their own error and result they will
16:09follow the same pattern again this is
16:11just a personal preference and now we
16:13are ready to do our login API and for
16:16that we're going to start being a little
16:18bit organized and we are going to add it
16:20into a web layer and eventually you want
16:22to move the other routes into the web
16:24layer as well so we are going to create
16:26it and we are going to create it as a
16:28folder because we are going to have some
16:29modules now inside our web modulebot.rs
16:33we're going to create another awesome
16:35module which is going to be for our
16:37routes login so now we can jump into it
16:39so so far we have created this structure
16:42which is we have our error for the crate
16:45eventually you might have errors for the
16:47main sub modules and then we have our
16:50web modules and some modules that will
16:53grow over time so first we are going to
16:56use our create error and result and then
16:59we're going to define the payload of the
17:02login what will be sent from the client
17:04so we're going to say login payload and
17:06that would be the username and the
17:08password and both will be strings that
17:11will be debug just for us and it has to
17:13be this allies from Saturday because it
17:16has to be this analyzed from Json to
17:17rest and now we're going to implement
17:19our login Handler and that is going to
17:23be an async function API login and we
17:25have our payload and now we're going to
17:27use the extractor Json which is a body
17:31extractor so you can have only one body
17:33extractor per rod and it has to be the
17:36last argument and now the type is going
17:39to be our login payload that we just
17:41defined below and I can return a result
17:43of Json of value from set adjson so
17:47we're going to make it simple for now
17:48and the reason why we can use our result
17:51is because the error Implement into
17:53response so everything has been wired
17:55now we are going to do our debug print
17:57and eventually you are going to have to
17:59implement a real database authentication
18:01logic but for now we're going to hard
18:04cut it so it's going to be payload the
18:06username is going to be demo 1 and then
18:08the password is going to be welcome
18:10and if not we're going to return early
18:13with the errors that we created login
18:15fail so so far so good later as part of
18:19the login we're going to create our
18:20cookies such as the cookie can be sent
18:23to the client such as the client can
18:24keep the session and now we're going to
18:27create a success body and that is going
18:29to be very simple for now it's just
18:30going to be a Json Json from Saturday
18:32and we're just going to have Resort
18:35success equal true and now the return
18:37we're going to have okay buddy and then
18:40that's it and that is our API login
18:43Handler for now the best practice right
18:46now is the router underscore something
18:48will have a function a public function
18:50which is going to be routes which will
18:53return the router of the whole module so
18:55that would be the convention that we are
18:57going to follow obviously you can have
18:59your own now we're going to have our
19:01router new and we're going to Route API
19:04login and that is a post so the routing
19:07post and we're going to give our login
19:09Handler we make sure to import water and
19:13now if we go back to our main.rs we're
19:16going to merge so that is we're just
19:17going to compose normally our web was
19:21login and Watts we're going to press
19:23save we go to our quick Dev we're going
19:26to split into two statements so we're
19:28going to have our request login we're
19:30going to do a do post on API login and
19:34then as a Json we're going to have our
19:36username demo one password welcome and
19:39now as a second statement we're going to
19:41execute it so we're going to do the dot
19:43await and the print data weight and now
19:46if we bring our quick Dev terminal press
19:49save we get our hello to mic and then if
19:52we scroll down we get our API login with
19:55our resource success so that is pretty
19:58good doesn't do much right now but at
20:00least we have it working and if we bring
20:02the backend terminal we can see that our
20:05Handler for hello to Mac was called and
20:07the Handler for API login was called as
20:09well so everything has that so now if in
20:12our quick Dev we're going to add the
20:14wrong password press save and in our
20:17terminal we get our internal server
20:19error with our unhandled client error
20:22and if we go to our server terminal we
20:24get our API login with a login fail so
20:27we have all the information on the
20:29server and right now we have close to
20:31nothing on the client which is what we
20:34want to start with Okay so let's get
20:36back to our working state
20:38and now the next step we can create our
20:41first layer and we're going to create a
20:44special layer so it's going to be an
20:45async function and it's going to be our
20:47main response mapper and that is a
20:51special layer in axon that take a
20:54response which comes back from the
20:55router and now it will return a response
20:59which can be the same because we are
21:01consuming it or can be a different one
21:03so right now we're just going to return
21:06the same and we are just going to do a
21:08debug print and then we're going to
21:10print an empty line and that will allow
21:12us to have an empty line in between each
21:15request such as we can see better as a
21:17request flow and later we're going to
21:20see how this main response mapper is
21:22going to become critical in how we are
21:25going to 100 our server and our client
21:27error so now the way that you add a
21:30layer or middleware into our router is
21:32with the method layer you use a
21:37and we are going to use a special
21:39middleware which is going to be the map
21:41response and we are giving our main
21:43response mapper function so now if we go
21:46to your quick Dev and you press save on
21:48your backend terminal we're going to
21:50have this little empty line because that
21:51is what we added at the end and we can
21:53print save again and we see again the
21:55spaces okay so now it's time to add
21:58cookies to our login and for that we are
22:01going to bring our cargo to ml and we
22:03are going to add Towers cookie so again
22:06most of the middlewares are part of the
22:10tower ecosystem and now we can add our
22:13cookie manager layer from the tower
22:16and we're going to call new now one very
22:19important point to understand is that
22:21the layer get executed from bottom to
22:23top meaning that if you want to have the
22:25cookie layer data in other layers of the
22:28middlewares they have to be on top so
22:30that is very important to understand
22:32we're going to see a high tracks later
22:33so now we can go to our Watts login for
22:37API login Handler and we can add an
22:39argument which is cookies which is of
22:42type cookies from our power cookies and
22:45that has an extractor implemented for it
22:47which now allows us to call the cookies
22:49to add a new cookie so for example here
22:52we're going to add a cookie
22:54Earth token and we're going to hard code
22:57a format right now which is user Dash
23:00the user ID the expression date of the
23:03token and the signature so that is just
23:05an example of a format for now now what
23:08we're going to do is we're going to take
23:09the orthogon and we're going to actually
23:12make it a constant on the parent module
23:15because that will be reused in other
23:17part of the system so we're going to
23:19take the auth token we're going to put
23:21it there and we import the web module So
23:24eventually you want to implement a rare
23:27authentication token generation and
23:30signature but that is not the topic of
23:32this video but this is a place to do it
23:34now if we bring our quick Dev and our
23:37quick Dev terminal and we are pressing
23:39save if we scroll down to login we can
23:42see that we have a set cookies and we
23:44have the cookie value that we just set
23:46and we have our response cookie because
23:48the HTTP response now has a cookie as
23:50part of it and then the HTTP client has
23:54also a install so that is part of the
23:56httpc client library and so we can see
23:59here the client cookies which is our us
24:01token and in fact if we were going to
24:04take our hello to mic on top and
24:06duplicate it after the login and press
24:09save we see that our first hello to Mac
24:12doesn't have any cookie if we scroll
24:14down to login we see that the cookie has
24:17been set we have it in the response and
24:21a knife was called down to the second
24:23Halo to mic we can see that he has the
24:26clam cookies so that is pretty cool okay
24:29let's remove our second metal to Mac we
24:32don't need it and now that we have that
24:34we are ready to implement our rest API
24:37and for that the first things we are
24:39going to implement is a model layer so
24:41we're going to have a model module we're
24:44going to jump into it and so the
24:46architecture that I like is this one
24:48where you have the web event contacts
24:50and model and store and today we are
24:52going to focus on the web layer which is
24:55our rest our Handler's middleware and so
24:57on the context which we are going to
25:00have a quick introduction later and the
25:02model which is what we're going to
25:04implement right now as a mock model so
25:07the implementation here is going to be a
25:09simplistic model layer and with a mock
25:12store layer embedded you don't want to
25:14use it for production but the goal is to
25:16have the model interface relatively
25:18close to where you want to land later
25:20such as then you just have to change the
25:23store layer and the model layer
25:25implementation but the rest doesn't
25:27really have to change too much so first
25:29we are going to use our create error and
25:32result eventually you probably want to
25:34have a model error and model result pair
25:36here I'm going to use 30 and because
25:39it's going to be extremely simple and an
25:41in-memory store we're just going to use
25:43the standard Arc and the text so in our
25:46first chord section we are going to have
25:47our tickets types so that is the item
25:50that we are going to have the crud on
25:52like a ticket is like a to-do like a
25:54task and the first one is going to be
25:57the ticket that are going to be saved
26:00and that is just going to have an ID
26:02which is a u64 and the title which is
26:05going to be a string and then we are
26:07going to have it clone because we need
26:11to store it but we need to clone it such
26:12as we can send a copy back to the client
26:15and then we're going to have our debug
26:17and our serialize because it has to be
26:19serialized to Json when we want to send
26:22it to the client let's make some room
26:24and now the second type that we are
26:27going to create is a struct for ticket
26:29for create so that is a payload that is
26:32sent for the create API and for now the
26:35only thing that the user can create is a
26:38title because obviously the ID is
26:40generated by the backend and not as a
26:43client so on this one we're going to
26:45derive it from this allies because the
26:48only thing we need is to disallowise
26:49from Json to rest so now that we have
26:52these two types and eventually you might
26:54want to have a ticket for a date which
26:56might have a lot of option properties
26:58such as it can be a partial update but
27:00for now we're just going to do the
27:01create the list and the delete so that
27:03will be plenty enough now we can close
27:06this section so one pattern that I like
27:08to follow is to have the model
27:09controller and for now it's going to be
27:12extremely simple it's going to be a
27:13model controller and it's going to have
27:15the store embedded in it and usually it
27:19will be more kind of a database
27:20connection or SQL X inside the model
27:23controller but right now the store is
27:25going to be embedded in it and it's
27:26going to be in memory so it's going to
27:29store it's going to be a Arc and we're
27:32going to put everything behind a mutex
27:34and it's going to be a vector so that
27:36will be our store and that will be an
27:38option of ticket but for our Mark we're
27:40going to use a vector ID as a sequential
27:43number such as is going to be our ticket
27:45ID and so we put it option such as when
27:48we are going to delete it we're just
27:49going to swap the option by node so
27:52obviously that doesn't work in
27:54production because that will be a vector
27:55in memory that would grow infinitely but
27:57for our mock store is very simple and is
28:01behind the interface anyway so now we're
28:03going to derive it we derive it from
28:05clone so that is important because that
28:07would be an application State and it's
28:09important to note here that the Clone
28:11doesn't clone the vector obviously you
28:14just clone The Arc and then we have a
28:16mutex that protects our Vector that
28:19makes the axis of our Vector exclusive
28:21now we are ready to implement our
28:23Constructor and it's just going to be as
28:25simple async new function that will
28:27return a result of self and in in the
28:30return of self we just need to have a
28:31ticket store and the arc and the default
28:34now because we use the arc default here
28:36we could also derive directly on the
28:39model controller such as we wouldn't
28:41have to implement a Constructor but in
28:43fact what you want is to control the
28:45signature of the Constructor early on
28:47such as then after you can swap the
28:50implementation with a real use case so
28:52by making it a sync and returning a
28:55result we are now sure that we can cover
28:57all of the cases and not paint ourselves
29:00into a corner and now we can create our
29:02crud implementation and one best
29:05practice that I like to have is to have
29:07different blocks of implementation per
29:09type of methods but obviously you can
29:11put everything in the same block this is
29:13just a personal preference so the first
29:15chord method that we are going to
29:16implement is going to be our create
29:17which is going to be an async create
29:19ticket we'll take a reference of self
29:21and then our ticket for create and it
29:24will return a result of ticket so the
29:27ticket that has been created we're going
29:29to get the store as a mutable from our
29:31ticket store we're going to lock and
29:33we're going to unwrap so that is for the
29:35mixt and now the ID and that is why it's
29:39a little bit hacky but it kind of work
29:40will be the store and the lens which is
29:43basically the end Express one and it
29:45works because again Ros guarantees that
29:48we have exclusive access to the store
29:49array read or write we send the text now
29:52we can do a ticket the ID and the title
29:55will be our ticket for create title and
29:58eventually here you can check if it's
30:00empty and then return a result if the
30:02title is empty or something like that
30:04and now we're going to push it into the
30:07store we don't forget to push it as an
30:09option because when we are going to
30:11delete it we are just going to take it
30:12out and leave a known over there we're
30:14going to do a ticket clone and then the
30:16original one we're going to return it as
30:19a OK ticket and that's it we have our
30:21crate now if we look at our list tickets
30:25it's going to be relatively similar so
30:28it's going to return a vector off ticket
30:29we're going to get our store we don't
30:32need mute anymore so we can remove it in
30:35this case it doesn't really matter
30:36because the lock is exclusive anyway but
30:39it's always good to have the intent
30:40correct and then we're going to have our
30:43tickets which is going to be our store
30:45we're going to eat there and then we're
30:47going to do a filter map and we're going
30:49to clone our tickets which is going to
30:51clone the options and because this
30:53filter map is going to exclude
30:55everything which is known so everything
30:57that has been deleted won't be returned
30:59and now we're going to collect
31:02and now we're going to implement the
31:04delete and eventually you want to
31:06implement also the get and the update
31:07but for this tutorial that would be
31:09enough so we're going to do the self and
31:11then the ID is 64 and then it will
31:14return a result of the ticket that has
31:16been deleted so it will return an error
31:19if the ticket wasn't found obviously so
31:21we're going to get our new store so in
31:22this case we need to have it mutable
31:24obviously we're going to get the ticket
31:26that has been deleted which is going to
31:28be our store get mute with the ID and
31:32now we're going to do and then so if
31:34it's found which is going to be the
31:36option we're going to take the value out
31:38and so that will return an option of
31:41ticket if it was found and so now what
31:44we want is to return an error if it
31:46wasn't fun so if we bring back our
31:48error.rs in our error NM we're going to
31:51add a section for our model errors and
31:54eventually those you will probably want
31:56to refactor them into the model layer
31:59obviously but right now we're going to
32:01put them there and it's going to be
32:02ticket delete Fair ID not found and we
32:06are going to have that as a struct
32:08variant such as we can name the property
32:10ID so now that we have that we are going
32:14to return a ticket we're going to make
32:16it a result with okay all and if it's
32:20known we're going to return our new
32:22error which is ticket delete file ID not
32:25found and the ID is that were given to
32:27us and that is the beginning of our mock
32:29model layer so now we are ready to go to
32:32our web layer and we are going to add a
32:34sub module which is going to be our
32:36routes tickets we're going to create the
32:39module and we're going to go to the file
32:41now we're going to use the model
32:43controller and the ticket types that we
32:45created and we're going to create our
32:47rest handlers and since we have done the
32:49heavy lifting and the model layer is
32:51going to be actually very simple so
32:53we're going to have our sync create
32:55ticket we'll return a result of Json of
32:58our ticket and here's a trick he will
33:00take the model controller as a state and
33:04we're going to see how we're going to
33:05wire the state later but this is the
33:07application State here that will be
33:09created and shared across all of the
33:11handlers and the state is an extractor a
33:13little bit like the other instructor but
33:15at the application Level we're going to
33:16have the ticket for create which is
33:18going to be our Json body extractor of
33:22the type ticket for grade the state type
33:24is an extractor for state and is
33:27actually a double struct so now we can
33:29destructure it directly in the function
33:32arguments and the same thing for the
33:33Json body and now we're going to have
33:35our debit print and we are going to have
33:38our let ticket we are going to call our
33:41model controller create ticket we're
33:43going to give our ticket for create a
33:46weight and now all the hard work has
33:48been done and so we can just return just
33:52we can do the same thing for the list so
33:55the list will return a result of Json of
33:59vector of ticket we have the same state
34:01at this point we're not going to have
34:03any argument for filter or includes in
34:05the list ticket that will be the subject
34:07of another video but obviously you can
34:09have more information and query
34:11parameters over there we're going to
34:13have our debug print and now we just
34:15list our tickets and we just return the
34:17tickets because again most of the hard
34:20work has been done in the model layer
34:22and then we are going to do the same
34:23thing on the delete which is going to
34:25return our Json ticket it's going to
34:28take the model controller as a state and
34:30then now it's going to take the ID in
34:32the path to respect the rest API on
34:35doing our debug print we are calling our
34:37daily tickets and then we return our
34:40Json ticket we make sure to include the
34:44and now we're going to create our router
34:46so it's going to be rods and now the
34:49routers need to pass the state so for
34:51that the routes will take our model
34:53controller as an argument and then we'll
34:55return the router we create our router
34:58and then we have our first route which
35:01is going to be on tickets and in fact on
35:03ticket we have two handlers one is going
35:06to be the post to create it so that will
35:09be our credit and then we can chain it
35:11with a get for the list tickets and then
35:15we have another route which is for the
35:17tickets slash the ID and that is by
35:21order it's not by name again and then
35:23we're going to have the delete the
35:25delete ticket and if you had a get
35:28ticket and an update ticket you would
35:30change them here because they will have
35:32the same route URI and now here's a
35:34trick to make sure that all of these
35:36handlers can get the states we do a whiz
35:39State and we give RMC and then that's it
35:42if you press save everything will
35:44compile nicely so now you can pass one
35:47state but actually aksama has a very
35:49nice way to be able to pass multiple
35:51States we're not going to use it but I'm
35:53just going to show it here so you can
35:55have a struct and you have App State and
35:57here we're going to have our sub states
35:59which is going to be our model
36:01controller here and you can have as many
36:03substrate as you want so here we are
36:05just going to do with one but you could
36:07have other ones like a radius connector
36:09or S3 or whatever you want to have and
36:11now you are going to derive it from
36:13clone and then from ref and from ref is
36:16a trait but is also a macro so you can
36:19implement it by yourself or if you use a
36:21macro like that then we need to bring
36:23our cargo to ml and now we need to add
36:25the version and the feature macro so
36:29that is a trick so once you have that
36:31you are going to have the from ref macro
36:34which will make every sub properties a
36:37sub state that you can inject if we go
36:41and we're going to create our Upstate
36:43and now we take the upstate now we go
36:46our we state which obviously cannot
36:48choose MC anymore but we are going to do
36:50Upstate and now that we have done that
36:52everything works as before so all of the
36:55Bindings that we have done in our rest
36:57Handler like State MC still work as
37:00before because MC becomes a sub state
37:03but your handlers and all of your
37:05middlewares doesn't have to know if it's
37:07a main state or substrate so that is
37:09extremely powerful we're not going to
37:11use it for now so we're just going to
37:13delete that and go back to our we State
37:18okay so now we can go back to our
37:20main.rs and the first thing that we're
37:23going to do is we're going to have main
37:25returning a result of void that will
37:28make things more convenient when we are
37:29going to initialize our model controller
37:31and now we're going to initialize the
37:34model controller and for that we're
37:36going to have model controller new
37:38weight and question mark now that we
37:40have that we can merge our rest API so
37:43we could call merge but we can also
37:46merge it with a nest function which will
37:48merge all of the rods under slash API so
37:53all of the routes didn't have API so
37:55that allows us to prefix everybody with
37:57Slash API but the routes wouldn't know
37:59that they are nested below the slash API
38:03so that is actually pretty nice again
38:04from a composition standpoint and now
38:07we're going to have web rust tickets
38:10rods and then obviously we're going to
38:13give our model controller and we are
38:15going to clone here we don't really need
38:16to clone it because we use it only once
38:18so we could just pass it but we are
38:20going to do that because later we're
38:22going to use it multiple time now if we
38:24bring our quick Dev and we're scrolling
38:26down we can add our create ticket and
38:30that would be a post apis tickets and
38:33we're going to create our Json ticket
38:35AAA and then we're going to execute it
38:38and print it and then we're going to do
38:41the list as well as a one-liner so we're
38:43going to do a do get on API tickets a
38:46weight and print if we bring our quick
38:48Dev terminal press save
38:50we have our hello to make
38:59and then we have our posts on the API
39:01tickets to create we should return the
39:08we have our get on API tickets to list
39:12what has been created
39:14if we press save again we're going to
39:16have two items that has been created now
39:20if we go back to our quick Dev and we're
39:22going to do a do delete on the apis
39:26tickets id1 and we're going to await and
39:30print it we're going to press save and
39:32now we see that the list has two
39:35but the one has been deleted
39:38and if we go back up we can see that our
39:41delete an API ticket one has deleted the
39:44ticket of id1 now if we were going to
39:47press save again then we'll get our
39:50unhandled client error obviously because
39:52it fails because the ticket wasn't there
39:54now if we go to the server terminal
39:57we're going to see that for this Handler
40:00the delete ticket we have all of the
40:02information on the server side so that
40:04again is what we wanted we have a little
40:06alignment bug here we'll fix that later
40:08so let's delete the delete because we're
40:11not going to use it much anymore so now
40:13if we were going to comment out the
40:16request login so we don't do login
40:18anymore and we press save but we realize
40:21that our create tickets still work
40:25and Now list tickets still work so we
40:29don't want that because what we want is
40:31to require the user to be logged in to
40:33be able to get data or save data so
40:36let's Implement that and the way we're
40:38going to implement that is by
40:40implementing our first custom middleware
40:43so let's go to our web module so let's
40:46create a sub module for us middleware
40:48and we are going to name it MW for
40:51middleware underscore auth so that is
40:54going to be the module where we are
40:55going to put everything that relate to
40:57authentication so let's jump into it we
41:00are going to use our OS token and our
41:02error on the result and now the simple
41:05way of implementing a middleware is to
41:07implement a nothing function and we are
41:09going to prefix it with MW and this one
41:12would be a require auth so it would be a
41:14middleware that will require the
41:17authentication and at the beginning it
41:19will just check the cookie existence and
41:21the way you do that is you need to
41:23parameterize with B for the body and
41:26then you are going to return a result of
41:28response and the boilerplate code you
41:31have two argument at least which is a
41:38over B and then as a return of the
41:41middleware you are going to return okay
41:48so it's a little bit of a mass 4 but
41:50it's relatively simple and then it gives
41:52you a lot of power because that allows
41:54you to be in between the request Rule
41:56and the beauty about the middleware is
41:58that we have the whole power of the
42:00extractor model so now in the middleware
42:03like we had before we can use cookies
42:06from our Tower cookies and that will be
42:09the extractor that will give us the
42:11cookies so then after we can just do our
42:13ostaken equal cookies get our stock and
42:17cookie and then we're going to map it
42:19just to return the two string
42:22So eventually you are going to want to
42:24do where a second parsing and validation
42:27we'll do the passing later the
42:29validation will be the subject of
42:30another video but for now what we're
42:33going to do is we are going to take this
42:35option and return an error if the Earth
42:38second was not there so let's get our
42:40error file and we're going to have
42:43another section which is going to be our
42:45auth errors and we are going to do us
42:47fail no us token cookie so again the
42:51reason why I have this section here in
42:53the create error is that eventually
42:55those section might become some module
42:58errors but everything is kind of
43:00organized from the start and so now I'm
43:03going to do a Nokia error with the error
43:06we just created and we do the question
43:08mark such as we return early so if
43:11everything is fine if we do the OK index
43:14return otherwise it will return the
43:16error now if we go back to our main
43:19we're going to do a little bit of
43:21refactoring we're going to have our
43:22routes API which is going to be the
43:25route that we have over there we're
43:27going to put rot apis over there and now
43:30on the rods ticket we're going to add a
43:34rat layer which is going to be our
43:36middleware from FN so you could also
43:39Implement a struct to do your middleware
43:41but the simplest way and very powerful
43:43ways to use the from FN like that and
43:46now what I'm just going to give our
43:48middleware Authentication middleware
43:51require Earth now the reason why we have
43:54the right layer and not just layer is
43:56because we want this middleware to be
43:58only applicable to this router so the
44:01route hello and the right login won't be
44:04impacted by this middleware so that is a
44:07way to ensure that this layer is only
44:08for this one and it will only apply to
44:11the routes API now if we bring our quick
44:13Dev and our quick Dev terminal and we
44:16have our login not activated we're going
44:18to press save and now if we scroll down
44:21we see that our post on API tickets
44:27as well as our list tickets and if we
44:30bring our server terminal we're going to
44:33see that the first request works fine
44:34but the next one fell with a no us token
44:40and the same thing for the list and now
44:42if we activate our login
44:45we're going to press save
44:47now hello to Mac works we scroll down I
44:50API login was a success set
44:54the clan cookies and if we scroll down
44:57now we have our post on API tickets that
45:01has a US token cookie and therefore has
45:06and we have the same thing with our get
45:09that has a cookie and that returns a
45:12successful response and obviously if we
45:14press it twice we get two tickets and if
45:18we bring our server terminal we see that
45:20we had the errors before but then
45:22everything was fine so that's pretty
45:25so now let's go back to our
45:28middleware authentication module
45:31and so the first thing here that we
45:33forgot is we forgot to put our debug
45:35print so we're going to put it there and
45:37that is going to be nice because if you
45:39press save on your quick Dev and you are
45:42going to see that the require auth has
45:44been called on create tickets
45:47and not under Halo 2 and the API login
45:50so everything has been working pretty
45:53okay so now let's do some token passing
45:56so we're going to pass the tokeno format
45:59user dashes ID dot expression of the
46:03token not of the cookie and then the
46:06signature and that will return the Top
46:08pearl of user ID expression and
46:10signature the expression and the
46:12signature is not really the scope of
46:13this tutorial but we are going to pass
46:15them a string anyway so we are going to
46:17create our path token could take a
46:19reference but right now we're going to
46:20take the ownership and then it will
46:23return a result of the Tuple that we
46:26have above now one thing that we are
46:28going to use is regex and actually we're
46:30going to use a little library on top of
46:33the official regex which is lazy regex
46:35and that allows us to Lazy compile a
46:39regex once and reuse it many times and
46:42it's also had a pretty cool macro that
46:44we're going to see right now
46:46and then we are also going to do some
46:49prep here in our error.rs we're going to
46:52add a OS Fair token one format so that
46:56would be the error that we're going to
46:59so we're going to use a regex capture
47:01from our lazy regex and the ways that
47:04the rig X capture macro works is that
47:06Texas string literal has a rig X and
47:10that would compile it once take a
47:12reference of our token and then it will
47:13Loot on the Turbo with the whole token
47:16and then next the topper member will
47:19match the regas group below
47:21that is actually pretty cool
47:24and everything is reference of string
47:26obviously and it will return an option
47:28of this double and so then after we do a
47:31OK or with our error we just created so
47:35now what we can do is we can pass the
47:37user ID from a reference of Str
47:411264 and we are going to map the error
47:45to the same errors that we have above
47:47and we'll do a question mark and so now
47:49at the bottom we are ready to return the
47:52Topo with our user ID as a view 64 and
47:55the rest has strings so now if we go to
47:57our require auth we don't where we can
48:00update the code to pass the token and
48:03that will be our Topo so first we try to
48:05get it from the option and then if that
48:08works we are going to type it into our
48:10paths token and then we do a question
48:12mark to make sure we return early if any
48:15of those fail and eventually that is not
48:18the scope of this video we will need to
48:20do some token component validation to
48:22make sure that the user ID the
48:24expression and the signature or match
48:26and that in many ways is naturally
48:28dependent on any specific framework and
48:31will have a specific video for that so
48:33now if we bring our Watts login from our
48:36server and we are going to change the
48:39formatting of our token so we are going
48:41to break it and we are going to bring
48:43our backend terminal and then you press
48:46save on your quick Dev file button and
48:48now we're going to get this ausfel token
48:53our require auth middleware and we get
48:57but the two first requests works
48:59perfectly fine because I didn't have
49:02and now if we fix it we press save the
49:05server is restarting you press save on
49:07the quick Dev and now everything is
49:09working nicely okay so that is pretty
49:12good already now one of the issue here
49:15that the user ID is a little bit lost
49:16here in the middleware because let's
49:19bring for example the routes ticket it
49:21would be nice that in the create tickets
49:23Handler we get the user ID such as when
49:26we create the ticket we can give the
49:28user ID such as we have who created the
49:30ticket and in fact you will probably
49:32also want it to have in the list and
49:34delete ticket to check if the user have
49:36access or not to it so the way to do
49:39that is with extractors so we have seen
49:41how to use default extractors like query
49:44path and Json and external extractors
49:47like the cookies one but now we're going
49:49to see how to create our own extractor
49:51and in fact we don't only want to have
49:54an extractor for user ID we are going to
49:56make it a little bit more General and
49:58have it the concept of context so we're
50:00going to go back to our main
50:03and we are going to create a module CTX
50:06for context so like this it doesn't
50:08conflict too much with other context so
50:10the important Point here is that the
50:11context is at the root because it will
50:14be used by the web layer
50:16as well as a model layer
50:18so our context is going to be very
50:20simple for now it's going to be just a
50:22struct which is going to be a context
50:24and it's just going to have the user ID
50:26u64 and it's just going to implement
50:28clone because that would be pass across
50:31as in point and thread points and
50:33debuggles for us and now we are going to
50:35have the Constructor the design pattern
50:38here is that the context one is created
50:40cannot be muted at least the user ID
50:43later you might add some mutable cache
50:46specially for Access Control but for now
50:49for this video we're just going to have
50:51the user ID but this pattern can scale
50:53relatively well and so for our
50:55Constructor we're just going to do a new
50:57and it's just going to take the ID and
51:00it will return the context with the user
51:03and then we are going to implement our
51:06property assessors and for now we're
51:09just going to have one that will return
51:11the user ID so this way we make sure
51:14that nobody can change the user ID of a
51:17context that is not within this module
51:19now that we had that we can go back to
51:22our middleware authentication and that
51:26is where we are going to implement the
51:29extractor and we're going to create a
51:32code section for CTX extractor so a
51:36nexum extractor has one requirement and
51:38that is is a nothing trait which means
51:41that in Rust right now is not supported
51:43by default and so we need to bring our
51:46cargo to ml and import the async trade
51:49crate that with allow us to implement a
51:52trade that has an async function so the
51:55trade that we need to implement is from
51:58request Parts which come from the axum
52:01extract some module and that will be 4
52:04CTX and that takes a generic for state
52:07so s and the S requires send and sync so
52:11these two type of extractor one which is
52:13for the body which is more restricted
52:16and one which is from any other
52:18formation by the body so that is what
52:20we're doing right now and in another
52:22video we can show how we can do body
52:24extractors but this extractor will take
52:27information from the headers of the UI
52:29red parameter and so on which is what we
52:31want because we want to take it from the
52:33cookies so from the headers so now this
52:36trade has an Associated type which is
52:39rejection and that we can give our error
52:42here now we're going to make that as in
52:44trade because the method that we need to
52:46implement is going to be an async from
52:48request parts and the signature is a
52:52reference of mute of parts
52:54from the request http
52:56and then the second argument is a state
52:58which we are not going to use and that
53:01will return a result which need to match
53:04the error that we give in a rejection of
53:07self then we need to make sure to import
53:09the async trade macro and the CTX okay
53:13so now let's Implement that we're going
53:15to do our debug print and then we're
53:17going to have to extract the cookies
53:20from the parts and the way that we're
53:22going to do that is we're going to have
53:24cookies and in an extractor you can do
53:27path extract to give the type you want
53:30to extract which is cookies and that
53:33will be an awaken wrap for now now the
53:35extract come from the request part EXT
53:38so we make sure that we import that and
53:41now that we have the cookies so the same
53:44thing that we had to cook in the
53:45middleware we can paste the same code
53:47that we had before and now the only
53:49thing that we need to return then
53:51eventually obviously you want to do the
53:53token component validation so that
53:55didn't go away and then we're going to
53:57return OK CTX new and the user ID that
54:01we just passed and that's it we did the
54:03extractor for CTX and so now the cool
54:06things about that is we can go into our
54:09middleware require us and raise it to
54:12have our cookies here we just can have
54:14our CTX and here's a trick we can have
54:17result of CTX there's many ways that we
54:21can inject an extractor we can do the
54:24reserve the option and directly the CTX
54:26and we're going to see all of this
54:27option later and now that we had that we
54:30can remove all of this code because that
54:32was part of the extractor and now we
54:35just do a CTX question mark and so that
54:37will give us exactly the same behavior
54:39as before but now the CTX has been
54:42extracted with an extractor which means
54:44that now we can use this extractor in
54:46all of the rods so now if we bring our
54:49quick Dev and our backend terminal and
54:53we press save we can see that everything
54:55works as before so that's pretty good
54:57now even our quick Dev we are going to
55:00comment our login and we are pressing
55:02save now we see that on the server side
55:05we are getting the error all fair no us
55:08token cookie which comes from our
55:10require us middleware so now to really
55:13understand how the extractor works you
55:15can go to our require auth middleware
55:18and what happened if we just put CTX
55:21here we are going to comment this out
55:23because that doesn't make sense anymore
55:24now if we press save on the server and
55:27save onto quick Dev now we are saying
55:29that the require OS middleware doesn't
55:31get called anymore so we still have the
55:34error but it come from our CTX extractor
55:37so in a way if you require CTX in your
55:41handlers then it will make sure that if
55:44you don't do result of CTX option of CTX
55:46then you will show an error if you
55:48cannot get it so that almost
55:49accomplishes the same result now if we
55:52were going to in our code here if result
55:55to put CTX now we put option of CTX and
55:58press save on the server and in our
56:01quick Dev now everything works because
56:03it was an option it was just known but
56:05nobody said to fair or none so
56:07everything was fine so that gives you a
56:09lot of power so in fact he if we were
56:11going to add a debug on CTX and press
56:15save on the server under quick Dev we'll
56:18have our none over there so for now what
56:21we're going to do we're going to go back
56:22result of CTX and our CTX question mark
56:26and now we're going to enable that to
56:28make sure that everything works fine
56:30okay so now we are ready to use our
56:32context extractor so if we go back to
56:36our was tickets now what we can do is
56:40after all states we're going to have our
56:42CTX and that is going to be our CTX type
56:46and now I can add it to my create
56:49tickets which obviously is going to have
56:52a compiler but we're going to fix that
56:53next and in fact the way that I like it
56:56early is to add it also to all of the
57:00model crud apis because again eventually
57:03I'm going to use the CTX for privileges
57:06and access control as well and the model
57:09layer and not only at the web layer so
57:11we're not going to use it right now
57:13we're not going to implement the access
57:14control but that is to have the pattern
57:16right from the start so now we're going
57:19to go to our model controller in our
57:21ticket now we're going to add CID which
57:24is u64 and that would be the Creator
57:27user ID so that is one of the commission
57:29I have but obviously you can name it the
57:31way you want and then we're going to go
57:33to our model controller crud
57:37and we're going to add our CTX and now
57:40we can have our CID from CTX user ID
57:44and then we're going to add underscore
57:47in all of the model controller methods
57:52and now if we go back to our rewards
57:55everything comparison nicely and one
57:57advantage of that now is that even if we
58:00forget the required auth this Rod
58:03required to have CTX and even the model
58:06required to have CTX so we cannot really
58:08forget to pass it because otherwise it
58:11wouldn't just compile okay so now if we
58:14bring our quick Dev back and our quick
58:16Dev terminal press save we see that now
58:20we have our CID equal one
58:22and if we press save again because it's
58:24the same user they both have CID equal 1
58:28but the idea has been increased
58:31now if we bring back our server terminal
58:34we're going to see that our extractors
58:36has been called twice for each request
58:39first for the require auth and the
58:42second time for the create ticket and is
58:45similar for the other request so if we
58:47look at our code and we go back to our
58:51middleware us and go to our form request
58:54parts that we are going to do all of
58:56that for each request twice in fact the
58:59token component validation is going to
59:01be quite expensive because you probably
59:03need to connect to the database or some
59:05sort of cache and do the hashing again
59:07and all these kind of things so we want
59:09to optimize that and in fact the cookie
59:12middleware that we added does this type
59:14of optimization and the way it works is
59:16you create a middleware and we're going
59:19to call it our CTX resolver the
59:21middleware can use other extractors so
59:24it's going to have the cookies and that
59:26will use our cookies extractor and then
59:28one thing that we're not going to use
59:30but just to show by example here
59:32eventually you will also want to access
59:35the model controller which will be your
59:37database Connection in a way so now in
59:39the body we're going to have our debug
59:41print and then we're going to get our
59:43cookies exactly the same way as before
59:45then we are going to compute our result
59:48CTX and it defer a little bit we're
59:50going to do it with match and it's going
59:53to be very similar of what we did before
59:54with the OK or and the and then pass
59:57token then we have our OK arm
01:00:00where we will create the CTX if
01:00:03everything is okay and that is where we
01:00:05will have our expensive token component
01:00:08validation and the reason why I did with
01:00:10the match here is that usually you will
01:00:13need to have a sync and it works better
01:00:16like this than just having closure and
01:00:18map and and then so that is one way to
01:00:21prep the code for later but obviously do
01:00:24what works for you and then after we are
01:00:26returning however over here so now that
01:00:28we have our resource CTX we do not want
01:00:31to Fair on this function but what we
01:00:33want to do is to clean up the cookie if
01:00:36there is a result CTX error and it does
01:00:39not match the no us token cookie because
01:00:43if there is no cookie then we don't need
01:00:45to worry about it but if there is one
01:00:47and it failed then we need to make sure
01:00:50that we clean it for the client so when
01:00:52we have that we're just going to say
01:00:54cookie remove and we give the name of
01:00:57the cookie I'm going to import font our
01:00:59cookies so we're going to close this to
01:01:02make some room and now what we're going
01:01:04to do is store the CTX result into the
01:01:07request extension and so that is a trick
01:01:10here so to do that we do our request
01:01:13extension extension mute and that
01:01:16basically is an exception on requests
01:01:18it's like a data store by type so we're
01:01:22going to do insert and we can give our
01:01:24result CTX so it has to be unique by
01:01:27type otherwise it will replace whatever
01:01:29we have put before and now that we have
01:01:32that we can simplify our extractor so we
01:01:35go down for our CTX extractor and we
01:01:38don't need this code anymore because
01:01:40that completed once and we still need to
01:01:43return the result of CTX and so what
01:01:46we're going to do is get the extension
01:01:48we are going to get the data from parts
01:01:50and so the way that I like to do it when
01:01:52there is quite a bit of chaining is to
01:01:54put it in a temporary variable for now
01:01:56let's call it D doesn't matter we're
01:01:58going to remove it later and then we're
01:02:00going to do part that extension and then
01:02:03I can toggle the inlays like that and
01:02:05now that we have exertions what I'm
01:02:07going to do the get by type so we're
01:02:10going to use a turbo fish the result of
01:02:13CTX so that is a concrete type of what
01:02:16we want to get back and that will return
01:02:18an option of results of CTX an error so
01:02:22now because it return an option we want
01:02:24to turn it into a result such as if it
01:02:27doesn't have the result context in the
01:02:29extension it will return a new error and
01:02:31then our error will be something like
01:02:34ausfer CTX not in request accession and
01:02:37we're going to bring our error module
01:02:40and we're going to add this error so now
01:02:42that we have that that will return a
01:02:46result of a reference of result so we're
01:02:48going to do the question mark here and
01:02:50so it's fine to fail on the extractor if
01:02:53we don't have it we have to fail and
01:02:55then we are going to clone it and in
01:02:57fact we have an error because if we
01:02:59bring our error type so that has to be
01:03:02cloned so that we can return the result
01:03:04and now that we have that we press save
01:03:07everything Compares so obviously we
01:03:09don't need the D anymore so we're going
01:03:10to remove it now that we have done that
01:03:13what we want is go back to our main.rs
01:03:17and we are going to add this middleware
01:03:19just after the cookie manager layer
01:03:22because since we are going to need to
01:03:25cookie extractor which is provided by
01:03:27the cookie manager layer it has to be
01:03:29above it so we're going to do layer and
01:03:32then it's going to be a middleware and
01:03:34that is going to be from FN but because
01:03:37we have the state that we're not using
01:03:39but just to show by example we're going
01:03:42to say with state so that is a function
01:03:45that now we're going to give our state
01:03:47so we're going to call the Clone here
01:03:49and then our middleware our CTX resolver
01:03:53now if we press save and bring our back
01:03:55end terminal that will restart the
01:03:57server and then we press save on the
01:03:59quick Dev and now we have the request as
01:04:02before everything is working very nicely
01:04:04we still have R2 extractor so that is
01:04:08always the case when every time you call
01:04:09an extractor is going to be called and
01:04:11generated but now the heavy lifting is
01:04:14only done once and everything else is
01:04:16just a lightweight clone and then for
01:04:18the API login even if we didn't need our
01:04:21CTX because we put it at the routes all
01:04:24then everybody has a CTX resolver so
01:04:27that's why it's important to not fail
01:04:28but to make sure to capture the errors
01:04:30such as such as other middlewares or
01:04:33handlers can handle the case they want
01:04:35okay so now that is quite a bit on the
01:04:39extractor and the middle wire and now we
01:04:42are ready to beef up our error now
01:04:45there's two more credit that we're going
01:04:46to use and that is going to be the strum
01:04:48macro which is going to have some
01:04:50utilities for enum to stylize them as
01:04:53string and we're also going to use uid
01:04:57so we want to have a server error and a
01:04:59client error add a little bit more
01:05:01information but just what is needed so
01:05:03for that let's go to our error module
01:05:06and we are going to create a new name
01:05:09which is going to be our client error
01:05:11I'm going to scroll down we're just
01:05:13going to have few variants the first one
01:05:15is login fail the other one is no auth
01:05:18and we're not going to give any more
01:05:20details and then the third one is going
01:05:22to be invalid params and then the last
01:05:25one will be kind of a fallback which
01:05:27will be service error and for our
01:05:29convention which is a client side there
01:05:31are all uppercase snake case which is
01:05:34not the convention of a nomanium but we
01:05:37want that into our API result that is
01:05:39just a personal preference but if that
01:05:42is what we want we're going to add the
01:05:44allow no command case types and now we
01:05:46are going to derive the burgers just for
01:05:48us and then we're going to use strum
01:05:50macros and we're going to use a macro as
01:05:53ref STL so that will allow us to
01:05:56centralize the variant as a string and
01:05:59that is what we're going to send back to
01:06:00the client so if we go back up we have
01:06:03the error which is going to be our main
01:06:05error the server error and we have our
01:06:08client error so we want to be able to go
01:06:10from one to the other so now to go from
01:06:13our server error to our client error
01:06:15we're going to have a custom
01:06:16implementation which is going to be
01:06:18implementational error and is going to
01:06:21be a client status which is going to be
01:06:23the HTTP status and the client error
01:06:26that will take a reference of self and
01:06:28it will return a top model of status
01:06:31code and client error so that is just
01:06:33the API we came up with but obviously
01:06:35you can have your own but the point here
01:06:37is that these methods will know how to
01:06:40convert a server error to a client error
01:06:43and the status code so now we are going
01:06:45to do a match the first things we are
01:06:47going to have our fallback such as if
01:06:50it's not covered it will go to a status
01:06:52code of Internet error and we'll send
01:06:54back our fallback service error then are
01:06:57going to add the one for the model and
01:06:59so in this case for this type we want to
01:07:02have a bad request and valid params and
01:07:04then for our auth we are going to group
01:07:05them and we are just going to send the
01:07:07status code of forbidden and the client
01:07:09error by it will be no auth and then
01:07:12last we are going to have our login fail
01:07:13which is going to be a one-to-one
01:07:15mapping with our logging file but
01:07:17eventually on the server side you might
01:07:19want to know why the logging fail and
01:07:22obviously you do not want to send that
01:07:24back to the client because otherwise you
01:07:26are sending information back to the
01:07:28hackers and now one little things here
01:07:30is sometime when you are going to code
01:07:32to fall back might be random land so
01:07:36what I like to do is to allow the
01:07:38unreachable patterns which is the
01:07:40fallback at the bottom such as I have
01:07:42more flexibility but there's a point to
01:07:44argue that you don't want that such as
01:07:46you are strict about making sure that
01:07:48you are always exhaustive and you don't
01:07:51need a fullback for example now if we go
01:07:53back up we don't need to have a full
01:07:55response what we're going to to do is
01:07:58create a placeholder exam response and
01:08:01then we're going to put the error into
01:08:03the place order so here's how it works
01:08:05we're going to have a let mute response
01:08:07and we're just going to take the status
01:08:10code internal server error into response
01:08:13so that will create a response object
01:08:16and then it's important to make it mute
01:08:18because what we are going to do is unset
01:08:21the error or server error into the
01:08:23response so we're going to do a response
01:08:26the accession mute so same pattern that
01:08:29we had for the request that's why XM is
01:08:32very powerful and then you can do insert
01:08:34and then we're going to do self and
01:08:36again it's an insert by type and then
01:08:39we're going to return response so that
01:08:41is just a placeholder and the magic is
01:08:44going to happen in the map response
01:08:46middleware and one thing that we're
01:08:48going to do as well is we are going to
01:08:50use this little macro from strum to be
01:08:53able to have the variant name as a
01:08:55string so now if we go back to our main
01:08:58data s we're going to close Main and if
01:09:02we go down to our main response mapper
01:09:04this is where the magic is going to
01:09:06happen so first we are going to create a
01:09:10and that would be the uid to match our
01:09:12server and our client errors and now
01:09:15we're going to get the eventual response
01:09:17error so the way we're going to do that
01:09:19is we're going to let service error
01:09:21which is our error and it's going to be
01:09:23our response extensions we don't need to
01:09:27be muted at this point and we're going
01:09:29to say get Chopper fish error so that is
01:09:32our error type and now that we turn an
01:09:35option of error so we're going to have
01:09:37our client status and error here and if
01:09:39we have a service error we are going to
01:09:42call our client status and error that
01:09:44will return the Tuple of status code and
01:09:47client error so we'll have an option of
01:09:49status code and client error so now if
01:09:51we have a client error we need to build
01:09:53a new response and the way we are going
01:09:55to do it is error response we're going
01:09:58to get our client status error we are
01:10:00going to get it as ref because we are
01:10:02going to reuse it later for the server
01:10:04request logging then we are going to map
01:10:07it we're going to destructure it as a
01:10:10status code the client error and now we
01:10:12can create our client body so we're just
01:10:14going to have the error the type which
01:10:18will be our client error as ref but that
01:10:21is what strum is giving us and then we
01:10:23are going to have for example our
01:10:24request view ID which is going to be new
01:10:29we're going to do a debug print and now
01:10:32that we have this new body we can create
01:10:34the new response and so we're going to
01:10:36take the status code here we need to
01:10:38deal with runs it because what we had
01:10:40above was a reference of status code
01:10:43because we did the As ref and then we're
01:10:45going to have our Json of our client
01:10:48error body and then axum for this turbo
01:10:51Implement into response so we can just
01:10:53do that and that will give our error
01:10:56response an option of response which is
01:10:58what we wanted now a little assigned
01:11:00note here the reason why the dev walks
01:11:02so if you go to the status code here and
01:11:04you go into the code you see that the
01:11:07status code is actually of type copy so
01:11:09when you are going to The Ref it is
01:11:11going to actually copy it and so then
01:11:13after I can take the ownership but the
01:11:15status code is still available for later
01:11:16now that we have that later on we're
01:11:19going to build and log the server log
01:11:22line but for now we're just going to do
01:11:24the back print which is server log line
01:11:27the uuid and then debug of the service
01:11:31era and now as a return we are going to
01:11:34say return the error response if there
01:11:37is one or we are going to do our unwrap
01:11:39all the response that was already
01:11:41planned and so here we have our server
01:11:44online which will print our server error
01:11:47and if we open the whole map over there
01:11:49and here we print our clan body is the
01:11:52one that was sending back to the client
01:11:53okay so now if we bring our quick Dev
01:11:57server terminal and you press save on
01:11:59your quick Dev what we are going to see
01:12:01now is that we have the CTX resolver and
01:12:05all of the request flow and we have our
01:12:08server log line with our uuid for now
01:12:11there is no errors now if we were going
01:12:14to comment out the login such as we
01:12:17don't execute the login then if we press
01:12:20save again we're going to see that now
01:12:22we have the client error body we should
01:12:24type no auth in this case we have a
01:12:28with a full error and then we have the
01:12:32matching uuid in both cases
01:12:36obviously we have the same thing for the
01:12:38next request let's activate our login
01:12:40such as everything works nicely so now
01:12:43we are ready for the last step and that
01:12:45is to build and log our server log line
01:12:48and the server log line which is a
01:12:50request log line is different from
01:12:52tracing tracing is when you put debug
01:12:55and info and warning or whatever inside
01:12:58your code such as you can debug it but a
01:13:01request log line is one log line pair
01:13:05request with the error or with other
01:13:07information and if you do that early you
01:13:10can first just print it into the console
01:13:12log such as you can debug locally very
01:13:14quickly and then when you deploy it in
01:13:16the cloud you can push that to
01:13:19cloudwatch for example on AWS and then
01:13:22you can query that with some Cloud
01:13:24native tools so to do that if we go back
01:13:26up we're going to create a mode which is
01:13:30log so that would be for logging and now
01:13:33if we go to log we're going to in insert
01:13:37a city whiz which is a pretty good
01:13:39extension of seti and we're going to see
01:13:40why later we're going to import our
01:13:43create error and result the seti and now
01:13:46we're going to build our request log
01:13:48line and so what we want is to be as
01:13:50flat as possible and that is relatively
01:13:53important because in Cloud watch all
01:13:55this kind of queries of flutter ID is
01:13:57the simpler it is and if you start
01:13:58having too much nested it can get pretty
01:14:01heavy it's going to have some error
01:14:03attributes we're going to make an
01:14:05exception right now for error data which
01:14:07is going to be a value of Json so then
01:14:10after we're going to add our HTTP
01:14:11request attribute the path and the
01:14:14method name for now then our user ID and
01:14:17then finally we're going to add our uuid
01:14:19and our timestamp so our timestamp right
01:14:21now is just going to be the apoc time
01:14:23but eventually you want to have it is
01:14:2508601 we're going to serialize it
01:14:28because the goal of that is to serialize
01:14:31into a new line Json it will give us a
01:14:33lot of flexibility later and then we're
01:14:35going to use users keeps analyzing known
01:14:38such as all of the option doesn't get
01:14:41the Allies so at least we use the power
01:14:43of J Central so if we don't create too
01:14:45much noise when we don't have an error
01:14:47for example we don't have to serialize
01:14:49the error properties so now let's close
01:14:51that let's Miss some room and we are
01:14:54going to implement our log request
01:14:57function and the goal here is that in
01:14:59our response mapper we are going to call
01:15:01this function and here we are like
01:15:03getting all the information we need to
01:15:05be able to build our request log line so
01:15:08first we're going to have the uid which
01:15:11is the uid for the request the request
01:15:15method and the URI and then we have our
01:15:18CTX and the service error and the client
01:15:20error the client error we can consume it
01:15:23and actually the service error we can
01:15:25also probably consume it but right now
01:15:26we're just going to take a reference and
01:15:28then you just return a result of void
01:15:30because we don't need any data back and
01:15:33now we're going to do a quick hack right
01:15:35now for the timestamp temperature is
01:15:36going to be a system now with a Unix
01:15:39Epoch a production you probably want a
01:15:43e08601 and then we're going to have our
01:15:46error type which we are going to map
01:15:48from the service error so that would
01:15:50return an option and then we're going to
01:15:52have our error data which will do a two
01:15:55value and that also will be an option
01:15:57and then one thing that we didn't do is
01:15:59our error needs to implement serialize
01:16:02because now we're going to stylize to
01:16:04Json so we can bring our error and just
01:16:06add say arise and now another trick here
01:16:10when we're going to serialize the NM so
01:16:12we are going to split the tag which is
01:16:13going to be the name type in our Json
01:16:16and that will be the string of the
01:16:18variant name and then we're going to
01:16:20have the content which we're going to
01:16:22name data and that will have the data of
01:16:26each variant when there is some so now
01:16:28that we have done that everything
01:16:29Compares and we are going to create our
01:16:34with our uid our timestamp our request
01:16:37information our user ID from the CTX if
01:16:40there is one and we are going to
01:16:42duplicate the client error type so this
01:16:44way we can do some matching if we want
01:16:46to do some search without having to look
01:16:48at what the client has and then we're
01:16:50going to have our service error type and
01:16:53our service error data and now that we
01:16:55have that we're just going to print it
01:16:57right now as a Json line but eventually
01:17:00you want to send that to a cloud watch
01:17:02type of service so now that we have that
01:17:05we need to make sure that we get all of
01:17:07this information into our map response
01:17:10so for that we're going to go back to
01:17:11our main and in our main response mapper
01:17:14now we need to make sure that we are
01:17:16capturing all of this information and
01:17:18that is again the power of XM with the
01:17:21extractors because we can just get the
01:17:24extractors from all of this information
01:17:25so for CTX our URI and our methods
01:17:30and now we are ready to build our
01:17:34we're going to extract our client error
01:17:36so that will give us an option of client
01:17:38error and then after we can call our log
01:17:41request with all of the data that we
01:17:43have and then by the way here there is a
01:17:45trick of unzip it's putting it it allows
01:17:48us to get the option of client error
01:17:51from the option of the topper that we
01:17:52had above so for example if we go back
01:17:55to the source that will be an option of
01:17:57status code and client error but we just
01:18:00need the option of client error so what
01:18:03we're going to do is unzip which now we
01:18:05have a table of option of each so there
01:18:07will be both sum or both noun obviously
01:18:09but then we only want the second one so
01:18:11we're going to do a DOT one and that
01:18:13will give us the option of client error
01:18:15and that is what we need over there so
01:18:17that is another cool little thing from
01:18:19option and so now we bring our quick Dev
01:18:22or backend terminal we press save and
01:18:26now everything works fine and we have
01:18:28our request log lines one pair request
01:18:31and now if we deactivate our login
01:18:34then we're going to have our client
01:18:37error and our log request with our
01:18:40client error type
01:18:41and our server error type with all of
01:18:44the data and then we have our matching
01:18:46uid between the server and the client
01:18:49and that when you do a production
01:18:51application this is gold
01:18:54and that would be it for today if you
01:18:56are still here congratulations you want
01:18:58from beginner to Advanced in action
01:19:00which is really an awesome web framework
01:19:03it's not too high not too low very well
01:19:05componentized and very complete
01:19:08until next one happy coding