In this video, I'll show you how to create
a Swift UI app that uses our custom Vapor back end API to read
and write data to a database. Hey, everyone.
My name is Mikaela Karen. I'm a full time iOS developer, and recently I've been learning Vapor,
so I'm excited to share with you how you can use Vapor to make
your own API back end. Okay.
Now let's create the iOS application. So just go to Xcode
and do file new project. Then here make sure you select iOS
and then click on app and we will call this YT Vaporios app and we will change this. So it is in Swift UI and this is Xcode 13. So this is what it looks like. You don't have to select lifecycle. I don't think anymore. So this is that and then click on next. But go ahead and find where you want
to save your project and click on create. Okay.
Our project is created. Let's go ahead and run it. We're just going to use
the simulator rather than my phone. So we have created our project and then
we built it for the first time. So we know everything's working. I'll keep that up and we can turn on the preview. I don't use it that often, but we can put it there. But let's go ahead and make
our file structure. So we will be using MVVM,
which is model view view model. So let's go ahead. Right click here and click on new group. So we have models. Come on. We have view models. I don't know why mine's doing that. Mvv and the models view models. And I like to put these in alphabetical
order just because I think it's easier. So move that one up here and we'll
also create one called utilities. And then I'll put that one down below. Okay, first thing we are going
to do is change the content view. Instead of being called content view. We're going to call it song list. So we right click on that
and click on refactor and rename. You want to click the plus here. So it renames the comma itself and you can
see it's going to rename the file too. So now we have a song list and then let's go ahead
and drop this into the views. Just expand all these. And first thing we need to do is create our model because we
have to model our data somehow. So we do file new file. We want to make a Swift file.
Okay. Let's call this song and create a structure for the song
that we made in our API project. We will make it conformed to
identifiable and codable. So the codeable so we can
decode and encode everything and identifiable is because it has an ID
and we will be using a list in Swift UI. There we go. So that will go away because it now
conforms because we have an ID property. Okay, let's make our song list. Open up song list here. Maybe one day the preview will work, but let's go ahead and make the list. So we wrap it in a navigation view, make our list, and then we need our data
to be represented somehow like an array. So let's go ahead and also
have a view model for this.
So we right click View models new file on a Swift file, and I will call it Song List view model. Make sure that is checked down here. Click Create. Let's go ahead and create just an array in here. So we have just our songs
array and it's an empty array and it's a published value. So if we go back here to song list, we have our view model. Is this ever going to build? Oh my goodness. Okay,
we are making a list and we want to iterate through all the objects within
our songs array inside of our view model. So let's type A for each loop and I will make this smaller inside of our list. We are going to have just instead of a label. We're just going to use a button because we will make it so you
can tap on every row. And I just have the text
as the song's title. And then we set this to font three, and then the foreground color is label,
which is a systematic color. So when it switches from light mode
to dark mode, it'll automatically switch and we don't have to manually
say what the color should be, and we will add a navigation
title as well. So we don't see any data because
we don't have any in the preview. Okay, so let's fetch some data
from our API. So in our view model, we will
need a way to get that data. Let's create a function called fetchsongs. Okay, so we will be using async await
for this, which is only available. So right here you can see concurrency
is only available in 150 or newer. So let's open the side panel back up again. So I did that with command zero and click on our project
and let's set the minimum target to 150. So we don't get that warning. So 150 right there when that target is selected and then make
sure it says 150 for that one as well. You can see these two different targets, rolled the target in the project
and there we go. So reset that and save it. Close this.
And if we build project again, this little
warning should go away. Okay, our project says build succeeded.
So we're good. And then that warning
doesn't come up anymore. To fetch our data, we first need
to say what URL it's coming from. So in our API we had URL was 127 one,
but that's not really a real address. That is just the name of our computer,
which is also called localhost. But everybody's computer is called
localhost, so we can't just hit that URL. So we'll solve that in just a second. But before we do that, let's first create the code that will actually
go about fetching the data. So what we're going to be doing is
making a single ten called http client. So go ahead and click on utilities and
create another new file. I'll make it a Swift file. Write http client and hit. Okay, so this is what makes it a single ten. We don't have an initializer so you can't
initialize this object, but we can access it through this
shared property that we created. And then that is what accesses all
the different properties and functions. So we want to fetch data. Let's go ahead and make
a function called fetch. As you can see,
this is a generic function. So what we are going to be doing is making our http client generic,
so that really it could be adopted. You could copy this code and drop it into any project that you
have that makes http request. So the generic means this is the value or the property that we're using called tea,
and it just needs to conform to codable. And then what we return is our object,
which is an array of T objects. And for us it will be the song model. But again, you could drop this code
into any project and it would work. So how do we do this with async await? We first need to make the request for fetching data. So this is the async version of
the shared data task. And when we use async await, because this is an asynchronous function,
we have to have the await in front of it. Meaning wait for this to finish. And don't worry about this. It'll go away in just a minute. And here we are going to check that our
response first is an http URL response. And then this property or type
has a property on it called status code. And we want to make sure that's 200
because 200 means it was a good response. And then we are going to throw an error. So first let's make the kinds of errors
that we'll be throwing. Put that right up here. So these are different types of errors. So if we get to this point, we know that it was a bad response back
if it was anything other than 200, and now we need to decode the data
and put it into whatever type T is. Here.
We have an object and we are going to decode it using
a JSON decoder, and it will be of type T, and it's an array of those objects. And we are decoding the data
that is right there. And then if that doesn't work,
we will throw the error decoding data, and then we will return the object. So that's what's returned out of this. So let's go ahead and build the project. Okay. If we build the project,
it succeeds right here. I had accidentally Typed data, not data
or I type data task rather than data. So this is the asynchronous one and you can tell when you command click on it
and it goes to QuickHelp. You can see it has the word async in it, and it tells you it retrieves content
from our URL and delivers the data asynchronously and that's
exactly what we want. So how do we go about using this function? We're going to be using it inside of our
song list view model to fetch objects. So the first thing we need
to do is define our URL. So to do that, you're going to create a Constance file. So this URL won't really ever change. It is going to change when we
are doing the development work. But the actual URL that ends up
being deployed in the final video. It won't change. So let's go ahead and make
a constants file for that. So we create a new file
in our utilities folder. Create constants Swift, and I like to put these in alphabetical order sometimes,
and we will create an enum, so it will look like this. We will fill in the rest
of this in just a minute. But for now, this is all we need. And let's also create an enum. So this is our endpoints. We only have one because we're only reading and writing
to that one songs endpoint. So we just call the songs and in doing it like this, making enum
with a static variable, which is actually constant,
but it's still a variable. But the static variable allows us
to use this in a type safe way. So in case we ever accidentally wrote song instead of song,
every time you type this endpoint, you basically won't be able to do
that with this endpoint or with this object because it
will be completely Typesafe. So let's go here and see how we do that. Let's create a URL. So this is just a string. So we have constants
baseurl so that's the URL we will fill in right here and then plus endpointsongpoints songs,
and we will put a slash at this. So it'll be something like it will look something like this actually. So this is what is called the base URL, and then the endpoints are slash
whatever as after this. So if we go here. Yeah, that's fine. This is just telling us that we
haven't used this variable yet. So it wants to put an underscore,
but we will use it. This is a string too. So let's create the actual
URL object itself here. We have a guard because we want to make
sure that this URL is for sure a value and that it doesn't throw, because if you
look at the signature of this function, that's just the structure actual function. Can we go to that? Open up the developer Doc. Oh yeah, that's just initializing
in the URL, but it does throw right here. It creates a URL instance but with the
question Mark means it might be optional. So that means if it can't create a URL,
then the value would be nil here. If there's any illegal characters,
it would be nil. So using Guard, we want to make sure
that this definitely has a value in it. Otherwise we want to throw
the error bad URL. So let's use this. We will create a variable
called Song response. So this is how we use our async await function. So here's our Singleton http client shared, and we are using this fetch
function, and we're passing in the URL that we created right here. And what's returned from this is an array
right here. It said an array of T. But with this we are specifically saying
it'll be an array of song objects. And once we have all of our song objects, we want to set that into our
variable right there. We have to do this on the main queue
because that will update this variable. And with Swift UI it will
know to refresh the view. So this is something that must
happen on the main thread and then that's it.
So we can go ahead and build the project
and everything should build. But we can't actually reach our data just yet from our API because
for one, we don't have a URL filled in. Okay, we have built succeeded,
and we don't have a real URL here. Let's first CD into our API project. So this is what mine is called it's the Ytvaper API, and this
is just the branch name. If you saw this before, I broke up all of the files
of the project into different branches. So you can look at a specific branch to see all the code for that specific lesson rather than having multiple
repositories for each lesson. And we need to run our database. We need to run our database with Docker. Okay, the first thing we need to do is we
need to run our database with Docker and we need to run our API
so we could write Docker, compose up DB and run it from the command line. Or the other way is we can use the Docker
desktop application. So if you open up the container that we have here and that is the database,
you can just hit play or start. Okay, we have it up and running. And if we just click on this row, we'll see the same kind of output
that came in when we were on terminal. So this is just another way
to run the Docker container. So we have our database running right now,
but we need to run our project. We could go ahead and run it via Xcode, or we can just run it
on the terminal as well. So if you type the command
vapor run and hit enter that is building our project and running
it so that will build our project and run it all in the terminal
rather than running it in Xcode and you can see it's going and fetching all of those
different packages that we have. And this is the first time I'm running it
through terminal, so this may take a while and it's already in use.
Okay. Mine came up with that error again. That address is already in use. So we need to fix that
by running the command lsof I 80 80 and we can
see postman is using that. But that one killed postman last time. So let's use this PID. So kill nine.
Then the PID number hit enter and then else off and that's gotten now. So let's type vapor, run enter and then now the project should try to build again and run all in the terminal
rather than running it from Xcode. We wait again.
Okay. Cool.
So everything worked. But again, we cannot hit 127 one at because
everybody's computer will say that. So it's literally not possible. That's just what the computer is called. So the URL we are going to use, we need to open up a new terminal
tab so we can't use this URL. But we do need this actually up and running because this is our API, and
basically it's like it's on right now. But we need something to bridge the gap
from the iOS app to go to our API. So for that, we need a new tool that I forgot to download
initially called In Grok. So it says it right here public URLs for exposing your web URL or whatever
that said for exposing your computer. So go ahead and just click
on this download button. You don't actually need to sign up for an account, even though
it does tell you to do that. Just click on download and it will
download a file called In Grok for you. So I don't follow this. I tried to and it did not work
on my computer to unzip it. And again, we don't have
to create an account either. We can kind of just use it immediately.
Okay. So once we have that downloaded, open up our new tab and terminal. Just typing CD and hitting enter
will give us our root directory, and mine went to the downloads folder. So when we type LS, we see our
file called Ingrock sitting here. So to use it, we do ingrocks, we type ingrock http.
80. 80.
So what we're going to be doing is like opening a Port on our computer,
and this is the Port that we want to use, which is the one that our API is using. So when we hit enter on this, we can see it brings up this window here is like this word forwarding
and this URL right here. So make sure to grab the one that's Https and you can see this URL
will reroute to localhost 80. 80, which 1270 one is
the same thing as localhost. So for the URL in our constants file, we want to put the same thing and don't
forget to have the slash right there. So when we hit our API and it says
right there too, when we hit the API, we'll use this URL, which that will
go to in grocery in groceries. That then that will forward to our personal computer
that says localhost 8080. So let's go ahead and run the iOS project. Okay.
And we can see nothing happened. The reason for that is because
we never called our function. So you have to call the function
for the function to actually work. And you see this output right here
about the navigation title. This is some just weird
thing with Swift UI. It has all these constraint
errors for this title. So if you remove that, that'll go away. But again, we need to call our function Fetch fetchsongs for it to actually
go out and fetch new songs. So if we go back to our song list, we want to add a modifier to our navigation view. So I'm going to close this so you can either grab it right
here and swipe it away or click on this button and it
hides and shows the canvas. So we want to add
a modifier to the navigation view called on up here. And from here we want to call our function
in the ViewModel called Fetch songs, so we can't just call
it directly like this because we will get an error telling us, come back here. There it is.
We will get an error first telling us we need this is an async function,
and this function doesn't support concurrency. So it's on a peer function
that doesn't inherently use concurrency.
Also, there's like four errors on this. And then the other thing is telling us this can throw and it's
not marked with a try. So if we look at the function here for one, it is async and two
the function actually throws. So right here it would throw an error. So when we use throws, we need the keyword try in front of it,
and then we have the other keyword await, which goes hand in hand
with using Async await. That's the pattern for concurrency code. And then this is the error that's again telling us that the function does
not inherently use asynchronous code like we haven't written right here. So to fix that, we can put this inside of a new task, and this task is
asynchronous. So if we look at the quick help for here a unit of Asynchronous work. So now if we build the project, this should build and be fine
with command B and there we have build succeeded. But this function can still throw an error, and we kind of don't handle
that immediately right here. So let's wrap this in a do catch block. Okay, we have wrapped our ViewModel
fetchsongs inside of this do catch block. So in case this ends up throwing an error instead of doing nothing with it,
we will print out the error. So this is just printing the word error. And then this is the error that's actually
caught that's thrown from this function. And then I use emojis in my code a lot. Just because it helps you see everything
in the debug log down here, especially when you have all
this constraint kind of stuff. You can just throw in an emoji
and then see it very quickly. Now that we have that we still have this running and you can see
it only says an hour and 54 minutes left. So after that time is over. This URL doesn't work anymore. So that's why we can
use it for development. But that's not what you end up using. Long term. Let's run our project now and we should see it actually going and fetching the data from our database, which is
just that single row of data. I believe the songs is money.
Yes. Okay. The project built and we
can see on the right. We have our one thing. The database that says money. So we have two outputs down here. The first one is in Grok. We can see that we did a get request to our songs endpoint,
and it came back with 200. Okay. And if we look at the vapor output when we did vapor run,
we can see almost the same thing that we did a get request
to the slashsongs endpoint, and that's about it. We don't actually see that it said 200, but we know that it worked because the data shows up here
and we didn't get an error thrown. So now that we can see data, let's add new data to our
database, but through the iOS app, let's stop the project and we can leave this running right now. So we want to add a new project by tapping a button in the top right
in the navigation bar. So let's add that with a toolbar. So we add this to the list property here rather than to the navigation view. Okay. So right here we want to have
a label called Ad Song. So if we look at this actually, we could try to look it in the canvas,
see if it works. My canvas doesn't work.
Usually it struggles a little bit
as opposed to running the app all the time in the simulator, because I do UI kit
way more than I do Swift UI still. And so I'm still used to just
always running it in the simulator. My computer is a little slow, so sometimes works sometimes doesn't. But we should have a button in the top.
Right. That is just the system
image of Plus Circle. So system image that is from here. So there's an app called SF Symbols,
and you can go and download that. I will have the link in the description below, and we would use
the one I Typed Plus here and you have all of these
different images that you can use. So if you right click it and then I don't know why we can't copy, but
the image name is whatever's down here I'm using Plus Circle, which is somewhere around here. I found it earlier, but you can use one of these as system
images in your code, and then these are just a ton
of ones that Apple just gives you. So we are using Plus Circle,
and I used a label rather than just an image with a system
name because this is more accessible. So if somebody was using voice over, this would say Add song instead
of just the words plus circle on it. And then you can see the database was hit a couple more times when we were
running this preview, but when we click the plus,
we want a modal sheet to come up. So let's build that part of it. So we are going to use the dot sheet modifier and put that
on the navigation view. So let's put it right
here before on appear. So an action sheet is what comes up where
it has those options at the bottom. But we just want to use a normal sheet. I'm not sure why my Xcode
doesn't remember what that is. We are going to be using this one
that says binding identifiable rather than just presented, which is just a boolean because the sheet that we're using, we will use this sheet for both
adding and updating values. So we need a variable that we'll use here
and we do want to do something for the on dismiss. So first before we fill any of this out,
what variable are we going to bind to? We are going to make a newenum type. So let's click plus and then new file and utilities and it will be a switch file called modal type. Okay, we have created a new enum
that conforms to identifiable. So in order to conform to identifiable,
it needs to have an ID. So here we are just creating a computer property and switching on ourself
depending on if the case is add or update, we are just returning the ID
of a string just called add or update. Then our two cases are add and update and update has an associated
value of type song. We'll see about using that later. So for now we have our modal type. So inside of our view model
or sorry, no inside of song list, we need to have a variable right here
that we'll be using. So we create a new variable called modal,
and it's a type modal type and we will set it
by default is nil because no sheet will be showing. And then that's because we
haven't Typed anything here we type modal because that's
the variable that we want to use. We will fill that in a little bit later. And for content,
I don't like the way it looks right here. So we will take off just by default. I don't like what the autocomplete does,
so we will take off that part. This is the content part of that closure. I just didn't like the way the auto
completes to look like that. And what we're doing right now this doesn't work because
we need to fill something in. But what we are doing right now is we have our modal type and then we were
switching on what that modal is whether ad or update was selected and we
want to show a different view. So we haven't actually created that yet. So let's go ahead and do that. So let's create a new view and it will be a Swift UI view. Let's call it add update song. Inside of this, we can do two things. We'll either be adding a new song
or we will be updating a song. So what will we be displaying? We are going to just put
a V stack on the screen that will have a text field property so we can type something
and it will have a button. So our ad update song also needs its own view model that we will use
to fill in some of these things here. So let's create that view model. Now do command n on our view models
using a Swift file. Add updatesong ViewModel and our view model will conform to Observable object because
it will be a view model. We'll wrap it in a
property wrapper on the view, but the first thing we need
is a published property and it will be an empty string. So that's what we will use
for a text field over here. Okay.
So we have our view model and it has
a property called song title. And then this is what's shown in the text field before we type anything
and it will just say song title. So on this will add a little bit
of styling, so it doesn't look weird. So here at the text field style will be a rounded border, so that will literally
just put like a Gray border around it and then add some padding so it's
not right up against the side. Let's fix this down here by just creating a new view model. But what do we want our button to say? So our button is either going to say add or it's going to say update,
depending on what this modal is doing, which will happen over here. Okay, so let's first make our view model,
so we will make the view model. It's going to have a couple
of properties on it, which will be a Uuid. So the song ID. This will have a song ID if it's
the update, meaning we're passing the song over to this view
and it won't have a song ID if we're adding a new song because we
haven't Typed anything in there yet. So we'll use the property VAR is updating to know whether or not this view is in the updating
state or if it's in the ad state. So when we type song ID
is not equal to nil. Well, if the song ID is not nil,
then that means we are updating. So is updating would be true. And then vice versa. And then I talked about over here. We don't know what we're going to write for the title of our button if it's
going to say add or update song. So we'll create another
computer property for that. So here we have.
We're checking again. If the song ID is not equal to nil, if it's not nil,
then we will say update song. We are using a ternary operator here. So then if this statement is false,
we'll say Add song so button title.
We can then copy this and put that in as text right here. Let's create a blank initializer and we will also have an initializer. And then we have another initializer
with our current song. There we go. We have another initializer that says
that Intake is a current song and we set the two properties
song ID and song title. But if we don't have a current song,
that means we're adding a new one. So right here it doesn't
take any properties, and this is fine to do, because every property we have in here
will have a default value of some sort. So this one is an empty string. That one would be nil. This one could be true or
false depending on that. And then again, this one
is one of those two values. So we want to add a new song. So let's create a function to do that. And the code for adding a song is going to look very similar to the code
that we just wrote for fetching a song, and we can actually go and probably
copy a majority of this. So we can copy this part because
we'll be doing the same thing. We have to create our URL,
and then we will use the base URL from constants and we're
using the same song endpoint. But what we are doing is we are sending a song to the database to the API,
so we have to create that song property. So here what we're doing
is creating our new song. It does not have an ID yet because we don't assign one within the iOS
app, and then we're using the song title. So that is whatever ended up
being Typed into the text field in the view. Now we need to actually make the URL. We need to make the URL request,
so we don't do that here. We do that inside of our Http client. So we have to make a new function
because we're not fetching data. We are sending data. So we'll make a new
function called send data. We will close that there
so we can see the whole line. So because we're using generics. Again, we have our type T,
which conforms to codeable. There we go.
And then we are sending it to this URL. I cannot type object. The object that we're using is of type T and then Http method, which we'll look
into, and then that will be a string. So the first thing we do is
we have a couple of Http methods. So we have seen two so far. We saw get and then post. So let's define those up here. And again, this is all
to make it type safe. So in case we accidentally spell post
wrong, it won't break all of our code. So this is an enum with a raw value. So we've used post and get and we have not yet used put and delete,
but we will get to those. And then with the raw value of string, the raw value will just
be the case itself. We also need to add a few other things,
and this goes with the URL request. So we'll look at these a little bit later when we kind of see it more in postman or I can open that now too. I already have that. So in postman when we did a create song, when we added a new song,
we didn't look at these headers. But this is what we're doing right here. So that said http header. So we added by default, it adds a header called content type,
and we set it to applicationjson. So that's what
these two things are used for. And then that basically just tells the request what kind
of data are we sending over? Let's go down to send data
and make our URL request. So here we are making our request. And what we saw in postman, I forgot to add the actual name URL here. So what we added was this is the
applicationjson part of the header. And then this tells you for header
field and the field was content type. So we see the same thing in postman. The key in value, which is sort
of the same thing is content type. And then we have application JSON. Everything else are like defaults. So that's why it says
auto generated headers. So we've added that to tell what kind of data we're looking tell the request what kind
of data we're looking for. I'm just going to enter there
to make this a little shorter. And lastly, we have
to send the data along. So we want to send data to our server. So here we have an HTT body and we want to encode our data from our object,
and then we encode it as JSON. So that's why when we went to send data, we had the body property,
and then this is our JSON object with a key of title,
and then the value of money. And right here we're telling it it's JSON. Now we actually need to make the request. So here we are doing the exact
same thing as we did at this part inside of the fetch function. So this is the same thing. Except we are passing a request
rather than passing a URL. We put an underscore here because we don't
really care about the data that's coming back because we don't actually
have any data coming back. We are responding to
the request with just a response. So that's what this value is. And then for those of you who don't know this is a tuple or tuple,
I don't really know how it's pronounced. And it allows you to kind of have two values that are returned out of a function
rather than just returning a single value. This is like a comma separated
list of values. So we have data and response. And then again,
we are checking the response that it is of this type and the status code is 200,
because if it's not 200, that means that it didn't go okay,
or it didn't go well and it failed. So now that we've created our Http client,
now let's go and use the client in our view model here. So what do we want to send. We want to send the URL. You can see it says
encodeable and decotable by default, because right here we say that T is of type codable,
and if you click on this and click help. So command click on.
This. Codable is actually a type alias
for decotable and encodeable. So we want to pass our object of song and http method that we want to use
instead of just typing post directly here we will use our enum and use the post and raw value. So I'm going to hit enter on this just to make it easier to read. And then that's all we have
to do to add a new song. So now we need to call
our add song function. But to do that, we can't just
call that directly in our button. We could for now, which I might do. Actually, it's part of the ViewModel. So we need ViewModel add song. We cannot just call ViewModel add song. We could, but we're using
this for both add and update. So we kind of have to have something here
that decides are we adding or updating depending on that,
we perform the right action. So inside of our view model, this is part of the view model. There we go. That one error should go away, but we have add updates song. So we have adding a song. But yeah, we need to decide
are we adding or updating? So here again we're calling this
and it's an async function. So we need to put it inside of a task. So how do we decide if we're adding or updating? We created a property
up here called is updating, and we can use that in our if statement. And by default if you don't type anything
like equal equal true by default, it says if this is equal to true, which is the best way
when using booleance. So if we are updating, if that's true, we want to update this on,
but we haven't done anything here. So let's put a comment updatesong function else we want to call our function add song. And again, this is an async
thing that throws. So we actually need to put try a wait on top of it or before it. And we want to handle what happens. So we want to put all of this
inside of a do catch block. So when this function, if there were to be an error,
we want the function to throw and actually handle the error as opposed
to having it just sort of disappear. So here we do that.
And then I added a completion handler on here because after
everything has been performed. So we go to right before the end of our task. I want to call our completion handler because when we call this function,
when we add something new to our database, we want to wait until this action
completes before we do something else. Like updating our view for updating
the new song in our list. We have all of this here. So now we can call this inside of our button. So we have our add update action. After we have done the action of adding or updating, we want to close the view,
which is one thing. So to do that, we first need
to add an environment variable, and this is how we can
dismiss this view after our song has been added. So once we do that, we can go back to song list, and now we can call the right thing here. So when we're right here we want to show add update song. So here now we're
presenting the same view. Except when we do add song, we give a view model with nothing inside
of it because there is not a song yet. Whereas when we do update song,
we are using this variable of song to then pass to the view model so it knows
what song we are then going to update. And we have this on dismiss code here
because at the point of after we have presented the modal type
something in clicked on the button. The view is then dismissed and we want to then update our view here
to show the new song inside of that list. Let's do that with our function of fetch. Okay, so we have ran the function inside of our task block because this is an async await function
or it's an asynchronous function and we are calling ViewModel
fetchsongstfetchnewsongs after the sheet has dismissed to get
updates from our database. Then we put this inside of a do catch again to handle the error
if it comes back. So we built the app and ran it. So now we should be able to click on run
and we should be able to type in new songs to add to our database and also read
all the songs from the database. Bad access. What is that about? So I'm going to clean the project and then
build it again because I'm not sure why that came up. So you clean your project
with commandshiftk. Okay, our project built and we can see that we have a new request here
through the songs endpoint because that's what runs when we load it for the first
time in this dot on appear. Let's click on the plus and I did not connect it because
you need to call the function and not just print add song.
Where did I do that? Right here. So we want to type modal equals
add because our sheet is bound to this modal property. And when we click on add song, we want it to present the ad
sheet, not the update one. So let's stop it and run it again and we see a new request here for
the songs endpoint and we see a new one right here because that's what we
did when we got all the songs. Now we click on the plus here and we see our modal pop up with the text
field on the button. So what song do we want to add? Let's add as brothers.
So if we type that and click on Add, we saw the modal go away and we saw
our data update right here. You can see in our logs. We did get songs first or
that wasn't the first thing. Yeah, it was. We did get songs when the view
loaded for the very first time. We did a post to create our new song, and then we did get songs again so
that we can update our initial list. And there we go.
We have successfully created new items and put
that in the database. And also we have read data from the database
to view in our iOS app. So to stop everything,
we can stop the project and to get out of this, you type Control C to stop our Vapor API from running,
and then to stop in Grok from running. You type Control C as well, and it'll
just go back to your downloads folder. That was a lot of code. What we did was create our folder
structure using MVVM model ViewModel. We created network Request using the new Async Await syntax with Swift 5.5 and we
made it generic so that we could drop this code into any other project that we
wanted to that uses network requests. Lastly, we used in Grok to connect
our iOS app to our local Vapor API. If you like this video, be sure to give it
a thumbs up below and leave any comments. If you have any suggestions on how I can make these videos better,
see everyone in the next video. When we learn how to update and
delete data from our database.