Swift Vapor Server Introduction

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

If you have questions ask on my site DzHaven.com and I'll answer there. DzHaven lets you ask questions and pay others who help you with an answer.

👍︎︎ 1 👤︎︎ u/dharric 📅︎︎ Oct 15 2020 🗫︎ replies
Captions
okay another day another video today we are going to get an introduction to vapor the swift server side framework um i'm gonna make this a two-part video series this first video is basically going to be an introduction so we're going to do some routing and learn about the fluent orm and then the second video i'm going to convert the server that we create into a graphql api service so um i'm going to assume you guys can install vapor on your own i'm not going to bother going through that it's pretty easy to do once you have it installed uh you want to create the project so i'm going to call it this and then it's going to ask if you want fluent my database is going to be postgres so this will open it up don't know why but sometimes the packages downloads takes a really long time and sometimes it's pretty fast but okay so as you can see we have our project the folder structure is there um before i get into it i want to talk about a couple of things in terms of um the underlying design and architecture of vapor so vapor is a lot like node and express underneath the covers vapor is using a library created by apple called swift neo and swift neo is an event loop based asynchronous io capable library so the vapor team is is basically reusing a lot of that functionality to create a web server so if you know anything about node and express that's basically the same thing right so you have node is a run time that among its capabilities it has an event loop based system for doing asynchronous um basically processing and express is a wrapper around that so you can think of vapor as pretty much the same thing um vapor to express and swift neo to node so as i said vapor is event loop based and the main um two constructs of this system are the event loop future and the event loop promise so um in in javascript you have only a single asynchronous object called the promise and it will either succeed or fail and then in either case um it will bring back a payload to the the function or code that has received the promise so it works this system works pretty much the same way but it actually has two object types one is the event loop promise and the other one is the event loop future so the event loop promise is basically um a lot like the promise in javascript it is the uh the processor so you have some code you're wanting to do it asynchronously and then at the end um the promise will you will use the promise to determine whether that activity was successful or whether it failed and then let me just write it out so it'll make more sense so off of the request object you're going to have the event loop and then off of the event loop you're able to create the promise and it's going to be of type whatever you're returning and then when you return you actually don't return the promise you return the future result which again in this case is this so basically what i think this architecture is is it's basically a pub sub but object based and the pub or the publisher is the promise and it basically publishes the results and then the subscriber is a event loop future so um if you want to think about it purely conceptually um the analogy that i use in my own mind is a company giving out a corporate cell phone so the company may send the employee out to the field with a corporate cell phone and uh tell the employee to wait until they get a call because the home office has to do some work first or has to sign a contract or whatever it is that they need to do and then once that work is done the employee will be notified either through a text or a voice call on the phone so you can think of the event loop promise as the corporate headquarters and the event loop future as the phone so anyway um continuing on so if we pretend that some work was done and that it was successful um and that it was successful so this is going to be success there's also a fail but let's pretend everything was successful and i'm gonna try to run this so as you can see the um the promise was created from the event loop which is coming off of swift neo again and then we pretended that whatever processing happened here was successful and uh we sent back the payload right and this is of course going to be happening inside of some asynchronous activity in here and then um this event loop future of payload string is returned immediately it doesn't it doesn't wait around for the asynchronous processing but like i said in the phone example although the guy got the phone the employee got the phone immediately he didn't get the call until the processing work was completed so that's basically what happened here um so i'm bringing that up because you're going to see this event loop future a lot especially when we use the fluent uh orm to access the database but so this is very important to uh to be familiar with so then the other thing to know at a very low level is um there are three ways to receive parameters for a vapor call so the first one is going to be through query strings so um let's get rid of this so as you can see this is a get call this as you just saw here in this sample url it's the sub url after the domain so we don't have any uh specific parameters but i'm going to create a a query string so again we use this and then we go to the query object and then we grab this query query string uh variable and then let's pretend that i'm going to stick it in here into the into the core message that's that's being returned and then i'll reload okay so i'll reload so this time it's going to be a query string it's going to be message and there it is so this is how you access the parameter if it were a query string and then the other ones are uh pretty similar so um in the case of parameters it's going to be and so what this means is it's being passed in on the url not as a query string but as like a sub domain value so that succeeded i'm going to reload again so that reloaded as you can see down here on the bottom right and then like i said it's not a query string it's like a sub domain parameter let's try a different name okay so that's the second method and then this one i'm just going to copy and paste it so this one is going to be a post so it's going to use the body parameter and i didn't want to get into this now but let's just do that real quick so this video is going to be about um basically a sample application that's like a to-do app so the reason why i'm creating this is um when you are receiving parameters um any really anything that needs to be decoded or encoded then you would inherit from this content protocol and then do whatever you need would add whatever fields you need to add so that's why i needed to show that and i'll explain later why this is a dto but just to focus on the the main thing which is to take parameters from a postback so i'm going to reload this and then once again it finished reloading so this time because this is going to be a post we're not going to do it off the browser i'm just going to use this um curl call so you saw before i had a title and a description field and this is a json request as you can see here and it's a postback so i'm only getting the uh the title i'm only putting back the title but basically what's going on here is you know the it's not called body first there is a body object here but it it doesn't grab it from the thing called body it grabs it from the thing called content and then it decodes it of type um to do dto type the reason why it uses type is because it needs access to the init which obviously cannot get from the object instance so then it converts it from json into an actual object because of course uh swift is statically typed so we need that and this is the previous code to create our promise and here i'm just printing out right here the uh to do parameter and then i say i succeeded only grabbing the title and then once again i return it so uh let's just see that again so right here that's that coming back so this was pretty fast i know but at the same time these are kind of um bread and butter functionality and features of vapor the promises and the event loop like i said most of the time you're not going to create promises yourself especially if you're using the fluent api you're just going to be getting back event loops with whatever the payload is but nevertheless the event loop is coming from a promise so it's good to be aware and then the three different ways of receiving parameters from the url so so now that we've kind of seen at a very basic level how vapor works um let's look at the project files themselves so um one of the really nice things about vapor is that a lot of the typical sort of activities that you would do are built in out of the box so for example in any any production app you're never gonna hard code passwords and and um ip addresses and stuff like that to servers you know in your code right so um it has built-in capability to read a dmv file to load it up and to run the configuration based on that file so part of the work of the bootstrapper is to do that and then finally to run the server application so i have a pre-made one i'm gonna i'm gonna copy that all right so i've copied the file over so obviously your file is going to have to have your own ip addresses and all that stuff and i've gone ahead and updated variable names to match the file so this is the bootstrapper that kicks off the server and reads the configurations and supplies them to the application the first thing that we have to do before we can actually move on is we have to set up our database now because we're using the fluent orm it can based upon the code that we provide in the migration which is inside of this guy it can create our database tables and fields for us so in this case oh and also i want to be clear on this so we have a model file and by the way this is coming out of the box you don't need to you don't have to um inherit from content in order to create a model you just need to inherit from model but it's here because i guess they're assuming that you might use it as a parameter but um this model although it's going to be mapped to the database and it has to align in terms of its fields and the table name it actually does not have any impact as far as the migration is concerned for creating the the table and the fields only the migration itself which is done by a struct or a class inheriting from migration and specifically in this function only what happens in here is what impacts the actual migration and creation of the tables so i just wanted to make that clear so we're going to update this file we're going to i just want to show you the database first so everything is going to go in this postgres database as you can see right now there's nothing in here as far as tables are concerned so i prefer caps so we're going to do that and let me make sure everything is matching and i'll explain these property wrappers in a bit so like i said this prepare function is coming off of the database it's going to generate a table and that table is going to start with an id of primary key of type uuid and you get all of that from this one call and then you have the field name you have the type which we're not going to use string because i found that string actually makes the type text and for such a small title i i don't think that makes sense so we're just going to use varchar and then required of course makes it a required field so let's just copy and paste these in so we need a description for our to do descriptions are not required so i'm not gonna have that now um i'm adding fields that are not in the model and again that's fine until we start using the model because the model is not tied to the migration so what i'm doing here is adding a relationship so we're going to create this user model and migration as well but that'll have to wait until i finish this section so when you're building a relation you indicate the type for the field in the other table and since it's the primary key it's always going to be required the um third set of parameters is um forget the swift nomenclature but basically you can keep adding more and more constraints going out so we're going to add the constraint for um the relationship so it's going to be to the users table and it's going to be on the field id because we're going to use the same mechanism as here and then i'm just going to copy and paste this code i'm going to add some auditing fields so these fields are going to be the same in users as in to do and it's going to be the created by um which is going to be required the last modified by also required um date time and i'll show you when i create the the model but basically it's going to become a time stamp and when you indicate at the model via the property wrapper that it is a timestamp these will get auto populated so these are not being auto populated so we'll have to populate them ourselves so i just want to make sure this compiles all right so then we'll go to the to do so i already updated the uh the field names so this is going to be the description and it's going to be optional so we're going to use optional field so we're going to have that and then we wanted to have that user relationship in our to do so we want to have an owner of every to do so you do that by referencing parent and um so this user id obviously matches the one in the migration which is going to be an actual field in the table the opposite side of this which is called children that's going to be in the users model is actually because this is a one-to-many relation relationship it won't end up being in the users table okay we didn't create this yet so all right so these are just boilerplate i'm going to copy and paste these from my code so obviously these are lining up to the audit fields that we just created in the migration um again if you notice that in the migration and therefore in the table these are required and yet in our model they're not required and like i said you can do the model however way you please if the model ends up being a content and you want to pass it in through your parameters you may not want to fill in these fields on the client side you might want to fill them in after you receive them from the client let's say you only want the client to provide the title and the description so you know you can still use this as a parameter object and then inside of your code on the server you can populate these two at a later time as i said before these will auto populate because they are time stamps so this is this default constructor is required internally vapor is using it so that's why we have that um i'm just going to copy and paste a convenience initializer because again it's just boilerplate stuff um actually this we don't need whoops too soon okay i'm gonna have to compile this in a bit but so basically you can see everything that's happening here um these guys i'm auto populating as the app so we know that this to do was inserted from the application as opposed to say some batch script or some other process so that's why i have these set to app these up here are obviously fields from the object type this if you notice is nullable um so the the reason why this is nullable on the model again even though it's not because this is a primary key it's not nullable is because vapor allows us to create this object without an id and then when it comes time to save it in the database it will auto generate a uuid for us so this is only true in the case of uuids it doesn't help us out if it's like an int or a bigint or whatever um this code right here is happening because this is a property wrapper so we can't use this directly we need the dollar sign and then we only need to populate the id to make the association vapor is going to know what to do with the rest of the data if it is needed meaning later if we call user dot username or whatever the field is okay so now i'm going to create the user model and this is going to be pretty much boilerplate code so i'm just going to copy and paste it so just remember you're gonna need a couple of new imports um again you don't need this just to create a model you do need this i actually forgot to talk about this on the to do but basically you do need this because it references the table that this user is associated to so then we have the same thing we had in the to do and then of course the user name that's really the only thing that's going to be in our table other than our audits and this relationship like i mentioned is based on the children property and then the user field inside of to do so this is referencing the to do object and it's property wrapper user and this entry will not appear in the database in the user database so we have the exact same fields for auditing we have this necessary default constructor and then here we're just setting the id and the username because there really isn't all that much to the the user so then we need to create a create user file so this is going to be pretty much identical not the same fields but the same methodology has to do so we have our schema table name primary id we're using again varchars instead of dot string custom means you can put any valid sql syntax in here obviously as long as it makes sense within the context and then we have our auditing fields by the way this create is when you want to create a brand new table there is also an update that you can use to modify but we're not going to use that um yeah so it's it's basically the same stuff we did in the create to do so let's try compiling so that was successful okay so we need to execute our migration but i realized that i had some bugs in the create to do i wasn't closing the parentheses over here so you might want to double check that and then if you go to the configure we need to add the create user migration on top because to do is having a reference to user so i did all those changes and then we can run the migration so you run it from the command line like this if you're running it for the first time it will take a while to set up but i've run it several times before so it says the migration was successful which means that we should see our two tables so you can see our reference is in the to do but no reference in the users okay so the next thing we need to take a look at is routing and models um so obviously we already went through this where we're looking at the route and we're looking at the result for sample purposes i only returned the string but we have our models and we can return the models from the urls but we could also accept uh models or uh data transfer objects as parameters now whichever method you use whether you wanna take your model and you know reuse it to become a parameter for a route [Music] or you want to use a dto you have to inherit from content so that when um it shows up in the parameters list from a postback it is decodable so obviously it's possible to do routes in this manner but a better design for larger applications is going to be to use a controller so when using a controller i just need to explain how the mechanism works first obviously you have to inherit from brow collection which to do controller does and then the beginning or the initializer is this boot function and basically the very first thing you do is you create this grouping for your specific controller now this grouping is actually a sub route it's a sub url off of the domain as well as being a label for your group so just be aware of that and then once you create that subdomain or sub url then you can add your http methods to it so in this case the methods are being associated to these functions and internally the functions are using fluent to access the postgres database now this guy right here is an additional grouping and therefore it's an additional sub domain or sub url i mean and when you see a colon it just indicates that this is actually a parameter so in this case you would have http the domain slash to do's then slash sum parameter which is going to be called to do id so in this case it's doing a deletion and this is the code that's coming off of the um off of the the template project so um we're not going to need a delete but it's there as part of the template okay so let's update this create to try and work in the way that we want so in the case of our data model we actually have two models the user and the to do and the user is the owner of the to do and referenced by the to do so in order to create a new to do we do have to get the user object off the database first and then we can create the to do and then if we want to we can return it so as i was mentioning before uh it's possible to use a dto a data transfer object to receive as a parameter instead of your actual model if you want to use the model you can just uh in either case inherit from content but because our model uh for the to do is um you know has various fields in it that are probably not going to be sent by the client in our case um the client is just going to be sending the title and the description and the rest of this stuff is just not going to be used at all so it's not um how should i say it's not a best practice to do that so we're in this example case we're going to use a dto and let me just show you the detail one more time so again you need to inherit from content that's what makes it decodable i believe internally there's a decodable that content inherits off of and then again we're just gonna send the two fields so so we do the decode and then we send the the type that we want to decode off of and we're sending the to-do dto type so that this guy can get access to the constructor internally and then we're going to like i said need to get the um the user object first so we can associate it to the new to do that we're trying to create so this um query is going to need the database object to access it and that can be had off of the request object so it's always available in there and then we are doing a filter and then the filter is going to take the field of the current instance and we're going to take the property wrapper username and we're going to compare it to in this case we're just going to compare it to john we're going to hard code it to john and by the way i already created an entry for a single user username john so just for demo purposes i'm gonna hard code the filter to look for john and then there's only one user and we only want one user so we're gonna take the first result and we're gonna try and unwrap it because these results are not nullable we're going to abort we're going to throw an exception if we find nothing so it's either going to unwrap or it's going to completely fail so um there's a couple of different uh how should i say methods to generating this event loop future um one of them is where you can just do a map and then that's going to be one to one so it's going to generate a new event loop future from some prior event future in the case of a flat map it's going to take something that could look like this and so on and then it's just going to flatten it down to a single so that's what the flat map does so in this case we're trying to create a new to do so we're going to create a new instance and then off of that new instance we can try and create it and i'll try and compile so that was successful so i just before moving on i want to explain something about fluent so there's three um basic ways that you can query on the database so you can query off of the main database object so we haven't done that but it's possible to do that you just need to pass the appropriate model the specific model that you're trying to query off of and then you can do your query that way you can also query off of the the type the model type and we had already done that right here and then for certain specific tasks you can query off of the instance right but if you're querying off of the instance then only certain things that make sense would become available so creating a new instance obviously makes sense so saving an existing instance is also possible and just be aware saving a new newly created instance is doing the same exact thing as create so just be aware of that okay so that's the only change that i wanted to make here and then since we are having another model i'm going to create another controller and in the case of the user controller we don't have anything pre-created for us so i'm going to create the whole thing myself so this is obviously for the fluent api and then certain things like the route collection or other protocols that you may need would be coming off of vapor so again the first thing you need to do is create the uh the bootstrapper basically the initializer so we are going to create a new group just for users and again this is a sub url so it's going to be called users so domain name slash users and then in here we're going to do a post method and we're going to create this function in just a moment and then since it's a post method we need some way of passing actually no we need [Music] a parameter for a get that i'm going to do so let's start with the get so again when you receive the request the databases actually database object is actually in there so we're gonna have this get call so that we can get the user object and retrieve their name and any other details that we might need so in this case we don't have an instance we're trying to get an instance so we're just going to use the model type so once again we take the current instance of the filter and we're doing a comparison so as i showed you before the three ways of getting parameters off of any request it's going to be the query string which is called the query object then we have parameters here and then we have the content when you're doing a postback so that's what we're gonna do and we only want one person so again we're going to throw an exception if it's not found otherwise we're going to return that one person so just for demo purposes i'm not even going to use it in the sample but just to show you another create so in this case i'm going to use the user just to show that it's possible to use the uh the regular model if you want to i don't think that that's a a best practice but it's totally doable if you want to so then we're gonna compile it now before we can run it we do need to make one more small addition since this is a brand new controller it's not been added by the by the template okay so the compile was successful and we're about to run it but before we can do that i forgot to mention this inside of here under options there is a working directory and it should be set to the root of the swift vapor folder um [Music] i did notice that the i get some odd errors i'm sure you saw this before something about the working directory was missing but it causes some other errors sometimes as well so just make sure that you have that set up and then we're gonna run the server so again the sub url is users and then it takes a parameter as indicated by the colon so we're going to and users and john and then you can see that the entire object comes back including the audit fields and the username and id all right so we've pretty much gone over all of the basics so what i'm going to do now is i have created this um swift ui project and since the focus of this video is the backend i'm not going to show you all the code or at least i'm not going to type it out but um basically let me first show you what this looks like no i do not want an ipod touch let's kill that okay so i'm sure you've seen some of this stuff blink and get updated here but basically what's going on is um each of these three sections i have as their own view as indicated here so the first one is just showing who the current user is then a form for being able to submit the user and then a list of to-do's that will show up as they get populated so this first one is going to be um this guy up here so all that i'm doing is i'm calling into our api server with a url session and um once i get back the data i'm just decoding it so then you end up with john in this case so obviously that works and then like i said this is a form and we're going to submit a to do in this case it's going to be a post submit and um just revisit the create so it's going to be this guy right here again the to do will have the association to the user and then once it completes successfully it will hopefully return whatever the result set is but in returning that result set it will kick off a reset of the list of to do's which is coming off of here it's an observable object which is acting as the environment object for the entire application and this guy is simply going in and calling the um the get all so every time a new one is added the get all is called and then get all is simply displaying them down here so if i go in here and i say to do abc description abc so if this call is successful then the set to do's will get called so then if i do y z and i just keep adding so that's it a quick introduction into vapor um if you're really into swift and uh whether or not you you know do android development as well but if you're really into swift this is definitely um a good way to continue using you know the language in your entire stack um there's opportunities obviously for code reuse uh maybe you can put some uh validation code certain bits of business logic and stuff into some common project as a swift package manager package and you know share it between the two uh the front end and the back end so and from what i've seen the the system works really well i mean it's very well thought out um the list of dependencies packages that you can use for various tasks is quite abundant there's support for my sequel there's support for uh redis sessions uh there's graphql that i'm going to be doing on my second video so um at version 4.0 it's pretty mature so you should definitely check it out and once again if you have any questions leave them on my site dzhaven.com and i will answer them there
Info
Channel: David Choi
Views: 1,850
Rating: undefined out of 5
Keywords: swift, vapor, microservices, swiftui, fluentorm, postgres
Id: bA9Ll6NGSj8
Channel Id: undefined
Length: 57min 17sec (3437 seconds)
Published: Thu Oct 15 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.