Transcripts
1. Lesson 01: Exploring the YouTube Data API: My name is Chris, and I'm
going to show you how to build this IOS app that displays
videos from YouTube. Now, here's what
the app looks like. You can configure the
app either to show individual videos or all
the videos from a playlist. Now, the data is being fetched through the YouTube data API. So if you modify the play list by adding
or removing videos, it'll automatically
be reflected in the app without having
you revise any code. Oh, and you can tap into
the videos to watch it as well or read the
video description. Alright, now let's
take a look at what skills you'll gain
after completing this app. After completing this app, you're going to get
experience working with the YouTube data API. You're going to also
learn how to send and receive network
requests from the app. In doing so, you're
going to learn a little bit about
IOS concurrency, especially using A Sync Wait. And you're going to
learn how to debug network traffic using Pxy Man, which is a free
third party tool. And that's going to allow you to troubleshoot anything that goes wrong when you're making
your network calls. And then when we get the data
back from the UTube API, we need to turn it into
something usable in our app. So that's where you're going
to learn about JSON parsing. We're going to need to store
our API key securely in our X code project so that doesn't accidentally
get leaked out. You're going to learn
how to do that. And as for the app side, you're going to
learn how to play UTube videos in your IOS app. We're going to use a
third party library called UTube Player Kit, and we're going to
integrate that library into XCode using Swift
Package Manager. Then you're going to learn
some swift DUI things such as using lists, geometry reader, a sync image, progress view, scroll views, just to name a few,
and a lot more, just in terms of building user interfaces and
capturing user interaction. Let's do a quick little
overview of how this all works in case you're new
to working with APIs. If you have used
the APIs before, then this will just be a
little review for you. Now an API is an
interface that you can connect to to send
and receive data. To put it in simpler terms, you can think of an
API as a collection of URLs that your app can access to retrieve
data or to send data. Now there are many
APIs out there. Some are free and some are paid. But most of the large platforms like Facebook, X Spotify Google, they all have APIs
for you to work with that platform or to
retrieve data from it. There are some APIs that
are just data focused, such as retrieving recipes or stock prices or weather
data, things like that. Being able to use APIs in your app is very, very powerful. What actually happens and how do you use an API from your app? Well, from your IOS app, you send a network request
to an API endpoint, which remember is just a URL. In your network request, you specify what data
you want to get back. In some APIs, you also have to identify yourself
in the request. This identification part
is called authentication. The API receives your
request and it will authenticate you and also make sure that your
request is valid. Note that not all APIs require authentication,
but most do. Now, if your authentication checks out and your
request is valid, then the API will
go ahead and gather the data and send a
response to your app. The response contains the
data that you requested, and it's typically in
a format called JSN. When your app receives
the response, it can read the JSN formatted
data and then convert it into data that can be displayed on the screen
for the user to see. This process of converting the JSN data into usable
data in your app, this is called JSN
parsing. All right. This is the process that
you're going to learn how to do with the YouTube API. Now let's take a look
at the YouTube API. Here we are the
YouTube Data API. You can visit this page at developers.google.com
slash YouTube. I want you to go under
this section that says Add YouTube data
and click references. And here you can see all of the endpoints that are available in this API for our app
to send a request to. Now, remember, these
endpoints, they're just URLs. So let's take for
instance, search. Let's look at overview first. This describes to you
what this endpoint does, how you interact with it, and it lists different methods, different ways you can
use this endpoint. So let's take a look at list. When you click into that, you see that change
to this section here and the common use cases. This is essentially searching
YouTube for something. You can search here some
use cases by keyword, which is probably
the typical example. Location live events or
your videos, for instance. If you scroll a little lower, this is the important part here. This is telling you the exact
URL that you need to hit. This is the endpoint, and
this is the request type. When you send a network request, it can be one of A couple a few different types, and get is the one
that is typically used for when you want to
retrieve data from the API. Not only do you need to
send a request to this URL, but you need to specify
parameters of your request. Remember. If you're searching for something on YouTube,
what are you searching for? You can't just say search. Here, these parameters, they describe what you
can specify along with your request in
order to tell the API what you want to retrieve or what you're searching
for in this case. Let's take a look here. One thing I should mention here is in the
parameter section, there's not always, but there
may be required parameters. Remember, in that overview, I said that the API checks your request
to see if it's valid. Well, if it is a
required parameter, then you have to specify
this information. Optional ones, you
can leave out, but the required ones, you have to include as part
of your request. What is this required parameter? This part, it's called part. This parameter specifies
a comma separated list of one or more search
resource properties that the API response
will include, set the parameter
value to snip it. So It's a little hard to determine what
these things mean. But what I'll typically
say is to try it out. The next step is
to track this API, let's set this parameter
to snip it as it says, and then let's see
what gets returned. And if it's not what
we're looking for, we can probably look at what else we can specify
for this parameter. Now what I'm looking for is, if we want to search
for something specific, like a keyword, where would we do that or
what would we do? This is searching by location. This is searching by event. This is searching for
types of channel. Specific channel you can look for how many results you want. This is the one.
The Qe parameter specifies the query
term to search for. If you wanted to search
for videos regarding, let's say, gardening, you would put the gardening keyword
in this parameter. I'll show you a little later how you assign that data
to these parameters, but we're not going
to dive that deep. Just wanted to give
you an overview of the YouTube API and all the endpoints
that are available. And also how these
endpoints work. You learned about the URL, this is the URL that you're
going to send the request to. This is your request type, and there are
required parameters that you have to specify, and there are optional ones that would give more context
for your request. Now, the endpoint that
we are going to use in this video series, Um, remember, this app, it can display
any YouTube video, and it can play it in the app. So for my use case, I want to display
a list of videos from a specific playlist because I have a
YouTube channel, and I have some play lists that I want to display
the videos for. So the endpoint that I'm going
to use is play lists here, and I'm going to use Actually, I believe it was I can't remember if it was playlist
or videos at this point. Okay. So let's take a
look at this endpoint. So here is the play
list endpoint, get. And if we take a look at
the use case, let's see. It retrieves all
playlists or yeah, all playlists for a channel.
That's not what I want. This one is, let's see. The request that I use
retrieves a specific play list, and I believe it was this
endpoint, because there is, let's see, the ID specifies
that we're being retrieved. Yeah. This is what I used. So instead of retrieving all
play lists from the channel, I wanted a specific one. So I had to include
this parameter here, which was called ID, and this is the ID of the specific
playlist that I want. And then within that play list, I also got the videos. After you complete this
video series and you follow along and you learn how to
use this YouTube data API, feel free to change the
way that the app works. You can implement search
in your app if you'd want. Just put a text field, when the user types
something in, call this call this endpoint. Pass in the keyword that
the user search for and return a list
of video results, and the user can play
it right in the app. What I'm going to show
you in the video series is using this end point, showing a specific
list of videos. Or you can curate
your own playlist or maybe curate specific
videos that you want to show, and you might use
another endpoint. So feel free to
customize the app. But I would recommend, especially if you're new to working with APIs
and networking, to follow along in this video
series, wait till the end, get comfortable after
you've achieved the result, and then customize it. Now let's take a look at
authentication because this YouTube data API needs
to identify who you are, before it's going to
give up its data. Now, before I show you the
YouTube authentication part, I want to point out
this line right here. These end points, they all have a quota impact and
tells you how much it costs to send a request and to get a response
from this endpoint, and that has everything to do with the authentication stuff. Now let's move on to there. Now we're going to
click on Guides. Typically with API
documentation, all the authentication stuff is all the way at the beginning. Here, it tells you
how to do that. Let's go into overview. Actually, let's go into
get th credentials here, you'll see that there
are two different types, two different techniques
that you can go about this. One is OOF and one is API keys. Now, most APIs will use one or the other,
and sometimes both. But if I were to throw
out a number out there, I would say 90% of APIs, you can use API Keys. Let me explain briefly the
difference between the two. API key authentication is where you sign up
for an account, and they give you a long string of letters and numbers,
that is your key. When you're making network
requests to the API, you're going to specify that key with your request and that way, they can associate that
request with your account. Then they can also
rate limit you. They can see how
much you're using the API, if you're abusive, if you are Yeah, mostly rate limiting, giving you quota and
things like that. Because You can imagine
if it's unlimited and as fast as possible and everyone is hitting their API, it could take it down or the server load
could be too high. This allows them to control
access to their API. If they find you to be abusive, they could ban your key, and you won't be able to
make requests anymore. That's how API key
authentication works. Now, OOP is a little
bit different. This is where you typically see a username and
password box in your app, and the user has to sign into their Google account,
and by doing that, they are obtaining a
token from the API. Then you attach that token to
the requests that you send. So there's a distinction
because now they're associating those requests with the user's Google account. So no longer are you
being rate limited. It's not counting
towards your quota, it's counting
towards their quota. Also what you can
do is different because now that Google can identify their
Google account, that user can perform things like liking a video or
subscribing to a video, you can call those
types of endpoints. Or perhaps following a user. Whereas API Key access,
all of your users, they're using the same API key, the one that that
you signed up for, that's associated
to your account. That's why with API keys, you can't really do things like liking a video or subscribing to a channel because the API
has no idea who the user is. All they can see is
that they can associate this API key to your
account that you created. OOF is a little
bit more involved, so we're not going to use
that in this video series. We're going to go through
the API Key route, and learning how to do
that is going to cover the vast majority of APIs that you'll
encounter. All right. So now let's go on to the
next step which is actually creating an account and
getting our API key. So all you have to do is follow this
credentials page link, and I'm going to open
it in a new tab, it's going to ask you to sign
into your Google account. Because I'm already signed in, it's brought me into this
credentials page of my project. You probably won't
have a project either. So let me try to go back
out onto the dashboard. You might have to go
through some onboarding questions or
something like that. But eventually, you'll
arrive at a page that looks like something like this because right here it's
saying I have a project, but you won't have a project. It might prompt you to
create a new project. You can go ahead and do that, or you can click on this
drop down up here, and then we can
choose new project, and we can create a
project together. Looks like I cannot
create a new project. But this is what you would do. You'd type in a project name. You would I don't think
this one matters too much. So you can choose whatever
and just hit Create. Then once you've
created a project, go ahead and navigate
to that project. So for me, there would
be this one right here. And you're going to
click on credentials, sorry API and services, and then you're going to
go down to credentials. Then once you get here, this is where you can
create the API key. So you're going to say
create credentials. Create API Key. It's going to
generate one for you. And then you're going to have to restrict it to the
YouTube data API. That would be good. Let me refresh the screen.
Did it do it for me? There it is. This is the new API Key that
was just created. I'm going to click into it. And then I am going to set
the restrict right here. I'm going to restrict
it to a specific API. The reason this is a
good idea is just so that if the API Key gets
into the wrong hands, I mean, it limits what they can do to just using the
YouTube data API. I think it's a good practice to not just give free
rein to everything. Restricting things and removing
options is always good, especially if you
don't need those options because it limits what limits any
unexpected behavior. Same thing goes for
programming, right. And I wouldn't set
restrictions on that. I mean, you could do this, but it's going to get It might interfere
with your testing, especially if this
is your first time. So let's just choose none. Restrict the key to
the YouTube data API. There's your API
key right there. You shouldn't be
showing this to anyone. I won't be using this key, so don't try to copy
it and use this key. I'll probably delete this after. But go ahead and save it. And there you go. You have a
valid key that you can use, and you're going to be using this key inside
your IOS project. All right. Now we're
set. All right, now we're ready to start
using the YouTube data API. In the next lesson,
we're going to build a test project
to connect to the API and to retrieve data
from it. I'll see you there.
2. Lesson 02: Getting Data from the YouTube API: In the last lesson, we went
through how to connect to APIs and we reviewed
the YouTube data API. We also created our API key. Now we're ready to start
retrieving data from the API. Let's dive right in. All right, so let's test out getting
data from this API. Now, before we get into
X code to try this out, there's an even easier
way that we can test out this API right from
within the documentation. They have this thing
called an API Explorer, and you can test
out the end points right from this panel. Now, all you have to do is
make sure that you're logged in to your Google account
in the upper right corner. This is the same account
that you created your API Key with
in the Lesson one. Remember how we had to log in to our Google
account and come here, create a project and
then create an API Key. What's going to happen as
long as you're logged into the same Google account is when you use this API Explorer, it's going to grab that API
key from there and use that. So let's test out the endpoint. Now, we're actually
going to use this one, Play list items endpoint. Because in the previous lesson, I talked about using
the Play list endpoint, but this one actually
just gives you information about
the playlist itself. Play list items, this is
the one we want to use. As you can see, this one, this is the URL that we have
to send the request to, this is the request type, and this is the only
required parameter, and you can specify different levels of detail
that you want to retrieve. Now, the reason they do this is because for your purposes, you might not need
all the information, and in that case, you can specify perhaps a
lower level of detail, and that would save bandwidth. Why retrieve more
information than you need? It's going to take longer, it's going to take
more bandwidth, and so on and so forth. I've figured out
that for this app, I need the thumbnail, the
video ID to display the video, obviously, thumbnail
to show the image. I need the title in
the description. And that's about it. And Snippet is the level of
detail that I need. It contains all of
what I just mentioned. Now, the other parameter
that I have to specify is the play list ID
because I want to retrieve all the videos
from a specific playlist. Now, when I first
used this endpoint, I made the mistake of putting the play list ID
into this parameter, but it didn't return anything, and I realized that, oh, I supposed to put
it into this one. So they'll make
the same mistake. Now, let me show
you how you can get the ID of the play
list that you want. So I've got a play list right
here that I want to use, and keep in mind you can use
any playlist that you want. So everything after this
equal sign right here, and before any ampersand, that is the play list ID. URL might have
something like this, let's say n t equals
one, two, and whatever. Between the equal sign
and the end sign. After list equals, that is your play
list ID. Don't worry. You'll find out really quickly if it is the play
list ID or not, because if you
don't get any data back from this API call, then you'll know
that that actually wasn't the play list ID. That's my play list ID.
I'm going to copy that. Then in my API explorer, let me full screen this. Maybe I'll just make the text a little bigger so
it's easier to see. Under play list ID, I'm
going to paste that. I have to specify a part here. Remember, this could
be content details, ID, status or snippet. Snippet is what I need. I it there. You can also see how it changes the URL that you're
going to have to send a network request to. If you take a look, this
might be interesting for you. This is the end point that
we're sending to hit the API, send a request to. Then the data that I specified here in the parameters,
it's all here. Look, P equals snippet, play list ID equals that ID, and then key equals
your API key. Now there's no textbox to
put in my API key here. So this is pulling from your
key that you created here. That's why you have to make
sure that you're logged in to the same account and because it's going to
go grab it from there. I'm going to uncheck
Google O Auth. I'm going to hit execute. If everything goes well, you
should get a 200 response, which means that
it was successful, and then you get
all this data back. Now, this is the JSO formatted data that
I was telling you about that comes back from the response from
the YouTube API. And it's up to us
to turn this data. Remember that process
is called JSM parsing, to turn this JSON data into
usable data within our app. You're going to
see how to do that in a few lessons in
the series, for sure. But for now, I just want to
take a look very quickly at the data that gets
returned and make sure that I have the
information that I need. Here I can see that I have
the title of the lesson, the description of the lesson, the thumbnails, image URLs, I have the video
ID there perfect. Then this is for Lesson two
and so on and so forth. I have everything. Now, if
you didn't get this response, maybe you got an error
or something like that. I would double check that part equals a snippet
spelled correctly. I would make sure your
play list ID is correct. Maybe perhaps you grabbed the wrong segment
of the URL there. Then I would also
make sure that I'm logged into the
right Google account that has access to the APIKy. And then try it again, hit cute. Now, if this doesn't work, for some reason, you
can't get it working. Don't worry, remember, this
was just a quick test. The real test is to be able
to do this inside X code, inside an IS app. That's what we're
going to do next. Don't worry if you
didn't get this part, this was a quick
test of the API. We are going to now start
our X code project. We're going to start
a test project. This is not going
to be our real app. I like to do when I'm
trying new things is to just open up a
new Xcode project, try something out, make sure I can get it working before I integrate it into
my main project. That's what we're
going to do here. We're going to create
a test X code project, and we're going to try this out. Let's do it. Let's create
our X code project. I am going to do this and
launch a new X code project. Under IOS, let's choose the app. Let's go next. I'm going
to call it test YT API. This is not our official app. It's just going to be a test. Interface is Swift GI, language is Swift,
storage is none. All of this is unchecked.
Let's click next. I don't need to create
a Git repository. I'm just going to create this on my desktop because it'll
be a throwaway project. Okay. Let us do this now. Make it a little
bigger so we can see, and then what we're
going to do is send that API call right when
this launches from here. I want to add a task here do task and open up
a pair of curly brackets. In here, we're going to make the network call and
print the results. Remember, I'm not going to
do things the best way. I just want to make
sure that I can connect to the API from X code. Receive the right
data back, right? We're testing at the API. And this is not
necessarily where we would do things as well in
our real project. Again, this is a test. I'll explain to you what
the task is a little later. I'll connect all
the dots for you. But for now, we're going to do it in this little task block. So I want you to type that out. And then let me type out some code statements and walk you through not code statements, but some comments and walk you through the steps
that we're going to take. So first, we're going to define the end point
URL with parameters. That's the URL that we're
going to send the request to. We're going to create
a URL instance. We're going to create
a URL request. Instance. That's the thing that we're actually
going to send, and then we are going to send
the request with r session. That's a mechanism for us
to do networking with. Then we are going to
print out the response. We're also going to have to
handle handle errors. Okay. Let's try this out now. First, let's define the end
point UL with parameters. If you take a look back at
the API explorer, here, you'll see that this right here contains
everything we need, except we have to insert
our API key right there. This is essentially the
UL that we have to hit. It's already written out for us. That's what I'm going to take. Now, one thing I
want to point out, which I'm not exactly sure why, if you take a look at
this endpoint domain, it says Tube dot google api.com. But if you take a look at this, it's Google api.com
slash YouTube. I've used both. They both work. This would probably be a
little safer to use because this is in the official
documentation, whereas this is in
this APA explorer, maybe it's just not updated. Ah, let's just use this and then we can
build it together. We can build up that
URL just so you also know you have an idea
of how it gets built up. I'm going to declare a constant. I call it URL string. Now, keep in mind, this is not how we are going to do
it in our real project. I'm just going to write
out the whole string here, including the API Key
and all the parameters. So to include parameters,
you put a question mark, and then from that point
on, it's parameters. And then the format to
specify parameters is going to be parameter name
equals parameter value. What is the first one
we should specify? How about part? Since
part is required anyways. So we're going to
type part equals, and remember you can specify
one or more of these. It tells you to specify more you would put a
comma in between them, but we only need snippet. I can put snippet. Now, to specify a
second parameter, you put ampersand and then the same Parameter name equals
parameter value format. What's the second parameter
that we want to specify? That's play list ID? You have to follow it based
off the capitals as well. Lower case P play list, followed by big I ID. Now equals, what is
the play list ID? And pull the screen up again and I'm going to grab
my ID from here. Now this actually makes sense. If you can see the URL, you can see play list, and then there's
a question mark, which means parameters
from now on. List is the parameter
name equals, and then parameter value. Then the end of the
parameter value is ampersand and then second parameter and so
on and so forth. That's why I say grab everything
after the equal sign, but before the Ampersand because that is
just the connector for the next parameter. That's my play list ID. So Let's put it
right there. I also need one more parameter. Let's put the ampersand sign, and this is key
equals my API key. Now, I keep saying this because I don't want someone
to watch this and say, Hey, you shouldn't just put
your API key there. I know. Again, this is a test, so this is how we're
going to do it right now. When we work on
the real project, we will secure the key. So let's go back
into our key here. I'm going to just show my key, and this is our test key. We're going to put it
right there. That is the URL that we're going
to send our request to. And this URL contains all of the request
parameters and the APIK has everything we need. Here, let's create
the URL instance. Let URL equals URL, and then we are going
to use this one here where you can just
pass in the URL string. But keep in mind that this
creation of this UR instance, it may it may not successfully
be able to create this, so we have to check. If you are familiar
at all with Swift, if you've taken some
courses before, you'll know what optionals are, and creating this returns
an optional URL instance, which means it may
not be successful. We have to check for that first. One way we can do
that is we can say if URL equals URL, right. What this does is it checks. If that is not NL, meaning that it was able
to successfully create it, then assign it to this constant, and then we'll move
that stuff in there, and then we can use it. But if it is NIL, it's just going to
skip and come down here and it's not going
to run any of this code. If it's NL, that
means it wasn't able to successfully create
the URL string, and we can't go on anyways. Now let's create the request. Let request equals URL request, and we're going to pass in this URL instance that
we created this one. This is what we created. This checks that isn't NL, and then if it's not
NL, if it's not empty, it assigns it to this,
and then we are passing that into the creation
of our request. Now that we have our
request in this constant, we are going to send the
request with URL session. This is URL session is what
we use for networking. URL session shared. There's a shared session
object that we can use. We don't have to create our own. And there is a method
called Data four. This is going to fetch the
data for a given request. Look it all connects. We can pass in this request now into this method.
But take a look. There are two keywords. There is a sync and
there's Throws. Those are two different
things that we have to deal with and we
have to observe. Let's talk about T throws first. This keyword indicates
that running this method or executing this task may potentially
create an error. It's going to throw an error. That's where that
word comes from. And you have to handle the error because you want
to respond to it. If something bad happens, you want to take note
of what happened, and then if it's
something that you can recover from, recover from it. If it's something you
cannot recover from, then maybe you display a message to the user and say, sorry, something bad happened or like this happened, we
cannot continue. Please try again type of thing. Or you can choose not to handle the error and just ignore it. That's perfectly reasonable
for some errors. That is what throws mean. And I'll show you in a sec
and how we can handle that. Now, Async is
another keyword that indicates that this
method is asynchronous. Now, we have to take
a little moment. If you haven't done
any networking before, let me just quickly describe it to you with this scenario. Asynchronous is
something like this. Let's say that You are waiting
for a package at home. It's a very, very
important package. They're not going to
leave it at your door. Let's say it's a new mac book. You bought a new mac book,
you're waiting for it to come. And so you're waiting at home, it's going to be sometime today, but you don't know exactly when it's going
to get delivered. But you really need to go buy some milk. Right?
Or maybe by lunch? Let's say you have
to go by lunch, and you have no food at home, you're starving.
So what do you do? You can leave and go
buy lunch yourself. But there's a chance that that mac book may get
delivered, and you're not home. You're going to miss it,
and that would be bad. Well, what do you do?
Well, it turns out, you have someone at
home, could be a mom, could be a dad,
could be a brother, could be a sister,
could be your spouse. You asked them, Hey, can you go pick up lunch? Because I need to stay home
and wait for this book. You send that person
to go bring lunch and that person goes and gets lunch while you can stay home
and wait for the package. That is exactly what's
happening here. Asynchronous means that Just like you're sending someone
to go pick up lunch? You are sending a
background task or background helper
in computer terms, they call it a
background thread? You're sending that to go
perform this network operation. Go fetch that data
from the YouTube API. While I remain here responding to user interaction and just like keeping
the lights running, you know, keeping
everything operational. And when you get the
response from the UTube API, they come back to me and let me know what that data is,
and I'll deal with it. Now, why is this important? Like how you had to stay home
and wait for that Macbook. If we get the main thread to go and fetch the data and send off the request and wait
for the data to come back, then there will
be no one to keep the lights running and
things operational. It your app won't be able to respond to user interaction
or do anything like that. So that's why with these
sort network tasks or some data tasks, you want to send a
background thread, just like how you sent a
helper to go pick up lunch. That's what asynchronous means. Okay. Now that you know what
these two keywords means, let's handle the
Throws one first because there's a
special syntax that you have to write
in order to capture the error or potential
error that can happen. Let's finish typing this out, and then we're
going to deal with these two keywords
one at a time. Data four, and we're
going to pass in request. Okay. So when something may potentially throw
an error like this one, what we do is we have to put
it inside a do catch block. So you do something, right? You do the thing that can throw the error in between these
brackets right here. So that's what
you're going to do, and then you're going to catch any potential errors
right below it. And then you can print out
any error that may happen. It's going to just
put it in there. Now, one more thing you
have to do just to indicate that something that you
understand that something can throw an error is you put a tri keyword in
front of it, right? So you're going to do this. You're going to try this, and then you're going to catch any potential error and
you're going to print it out. So that handles the Throws keyword for running this method. Now, let's talk about the async keyword that
we talked about. We want to send this task off in the background
to grab the data. And come back when it does. What we have to do is
put the weight keyword. What this does is
it basically says, before we execute any of the code below
this line of code, it is going to wait
for this to return. Why do we want to do that? Because let's say down here, we are going to print out
print out the response. Actually here, we're going
to put handle error right here and print out response, we're going to put
that right here. Right We wouldn't
want to print out the response before this comes
back with the data, right? Because then there'd be
nothing to print out. By putting the await keyword in front of an
asynchronous method, it is going to wait for this
to happen in the background. Finish doing its
thing, come back, and then we are
going to print out the response. What are
we going to print out? We have to assign
the data that gets returned into something first, just like how we did here, let URL equals that, let request equal that. We're going to say, let data, response, equals that.
Now, why did I do this? What is this? This
is called a tuple, and it's basically a
collection of variables. The reason I did this is because what gets
returned is two things. One is the actual data, the JSN data, and the
other is the response. There are two different things, and they will get assigned accordingly to data
and to response. Now when I print it out,
I can print out the data, and I can print
out the response. It's not going to run this code until this comes back because of this a weight
statement right here. Now I can explain to you
what this task keyword is. The task keyword is for running asynchronous methods or asynchronous code,
which is what this is. It's just a special construct to be able to run code
in the background. You think of it like that.
So now we're all set up. After writing all of that code, what we're going to do
is run this project. It is going to execute this code as soon as
the simulator launches. And then we're going
to see some output, whether it caught an error or we actually see the data
in the response. So let's take a look at
what's happened here. If I open up this console area, and if you don't have
this console area, it's actually it
might be minimized. You hit that button right there. And you might not
have these tabs. So you just just click
these buttons in the lower right corner
and open these tabs. There are two things
to notice here. This This is the data, and we can't see the data. It's just telling us
the size of data data. That's what happens when
you try to print out data. But we're going to have
to parse that JSON or convert that into
usable data in our app. We're going to do that
a few lessons later. But let's take a look at the response because this
can tell us a lot as well. Okay. So if you look for a status code status
code 200, that's good. Remember back here
in the API Explorer. I think, here it
is, okay. CO 200. That means that this is a
server code for successful. Server code 200. You can Google it,
server codes 200. Means. There are more codes. Let's take a look at
what we get here. Now, you can't actually
see the JSON data, but you can see some
details about the response. But status C 200, that is a good sign. That means that the API
accepted our API key. I accepted our request as being valid and it returned response. Let's take a look at
what happens if we just Change some of the data. Let's
say I mess up my API key. Where's the key? Right here? I'm just going to delete a
couple of letters from it and run it again and see what the
status code is this time. Is 400. That's 400 is not good. It probably detected the
APIKey is not valid. Bad request. Perfect. That's awesome. That's
exactly what we expected. Let me undo. The API
Key should be valid. Let me just mess up my play
list idea a little bit. See how that changes things.
It's a four oh four. What's a four oh
four, not found. It couldn't find my play list because I messed up
the play list ID. So this is really good. That means everything is
working as we expected to. But wouldn't it be great if you could actually see the response. Right here, we're
just looking at status code of the response. Well, sometimes when you're programming and you're working with networking calls
like we are doing now, it'd be super helpful to
take a peek into what the actual contents of the
response and the requests are. And that's where you use a third party a network
debugging tool. So I'm going to show you
how to use Proxy Man, which you can use for free
with your IOS app development, and then we can take a peek at the actual response and
we can see the data. So let's go ahead and download
and install Proxy Man. Go ahead and visit
proxy maan dot O, and you can download
the MAC app. Keep in mind, you can
use this for free, and there are paid features, so you can look into that, but I recommend just start
for free for now. Okay, so I'm going to
launch my Proxy Man. Now, yours might not look like this because they'll probably
be onboarding for you. You probably have to walk
through a few steps first. But one important thing
for you to do is to go down to a
certificate and you're going to have to
install a few things. So install certificate
on this MAC first and then install certificate on IOS and you're going
to choose simulators. But it helps if you actually have the
simulator up and running. So in your co project,
just run your project, so you have the simulator open and take note of what it is, IPhone 15 Pro because it's going to be installed
on this simulator. So, Yeah, this is what
you do. Okay here. Choose simulators. And then
it is going to first of all, this was installing
it on your mac. If you haven't done that, you have to click his button. And then it should say found the simulator because
you have it launched, so it's looking for it. I should say it's found. And then you are going to
choose just prepare simulators. And then it's going to
ask you to reboot it. You click this button and it reboots the simulator
with the new certificate. This will allow proxy
Man to stand in between the requests that your
simulator makes and receives, and that's how you're
going to be able to see the data, right? So what you're going to do, sometimes you have
to restart X code. It's a little
finicky. If you don't see what I'm showing you, then try restarting X code
as well as the simulators. But if everything is
set up correctly, then what you should
be able to do is if you run the app now, and you open up this Apps tab, you should see it appear here. There it is. That's my project, right. Let's see here. That's this one. Okay.
What I can do is right click and pin and
it'll show up up here, and you can see that it sent
a request to this domain. It was okay, but I need to resend the
request to see the content. Let me run this project again, and you'll see a second
request being made, and this time, you can see everything. Take a look at that. This side on the
left is request, this side on the
right is response. For the request, you
can see For the query, you can see all
of the parameters you specified, so there's key, there's play list ID,
and there's part, and that was all from the URL. But the response is
the interesting part. You can see the response code, it's right here, 200. But if you take a look
at the body right here. This is the data that was
returned in the response. Remember when we ran it
in the X code project, this data right here, we printed the data, and it just showed
the data size. Well, with Proxmn, we can actually take a peek into
what the data is here. Here's all the data. This is a very helpful tool to use when you are working
with network calls. Now, if you are having trouble
seeing what I'm seeing, I would recommend that you go through the
troubleshooting steps. Let's see here. When we chose this, there was some troubleshooting
steps you could try and launches
some documentation for you to try things out. This is what it looks
like. Yeah. Just go through this and try these
troubleshooting steps. Okay. Not the end of the world if
you can't get this working because as you can see, even without Proxy Man, we're able to send the
response or sorry send the request and get
the response and the status code
200 and all that. All right. Again, this
was a test project. This is not the way we're
going to do things like this. We definitely want to secure the key and do things a
little more elegantly, not just everything
in this content view. So we're going to create
a separate component to handle the network stuff, and we'll do all
that. All right. But this was a huge success
going through this part, and I hope you
learned a few things. Alright, now that we know we can connect to the API and
retrieve data from it, we're ready to start our actual X code project for the app. In the next lesson, we're going to start a
new X code project. We're going to store
the API key securely. We're going to start roughing
out some of the screens, as well as some of the components that
we'll need for the app. All right, I'll see you there.
3. Lesson 03: Creating the Xcode project, views and models: The last lesson, we're
able to connect to the YouTube data API and
retrieve data from it. In this lesson, we're
going to set up our X code project and all
of the views and the models. Alright, let's diver it in. First, let's start
with a little bit of an overview of how our
views will be laid out. I also want to explain how our data model is
going to look like, especially as we're going to interact with the
YouTube data API. So first off, we're going to
start with the home view, and this is going to contain a tab view with
additional views. Now, I know in this demo, we only have one tab, but this is set up with the intention that you
can add additional tabs. Okay. So the home view will
house the tab view itself. And then the tab view
will contain instances, one instance of the feed view. And this is that scrollable list of thumbnails that you see. Now let's talk about how the feed view is going
to get the data. We're going to create
a separate component, let's call that the
data service that is going to be
responsible for all of the code that interacts
with the YouTube data API. And the reason for this is so that we can keep
it all in one place, and it'll be easier to maintain and also to
troubleshoot and debug. So when the feed view loads, it's going to ask
the data service for the list of
videos to display. And then the data service
itself is going to be sending that network request
to the YouTube data API. So in the previous lesson, when we looked at
what got return, it was two things, really. There was an overall
play list structure, and then within that, there were individual video objects, right? Like dictionaries that
contained the video data. So we're going to be
parsing that JSON into a single play list instance containing multiple
video instances, each one representing
the video data. If you don't
remember, or you're a little bit confused,
don't worry, when we get to that part of
sending the network request, getting the data back,
and parsing it into JSO, I'll dive into more detail about how each piece or part of the JSN translate to different properties of the
video and playlist instance. So once the data comes back, we are going to see a list
of data in the feed view. So next, we have to fetch the video thumbnail image data because that image data doesn't
get return from the API. Instead, we just get URLs
to the video thumbnail. So we are going to use async
image to asynchronously. That means in the background, download that image
data for display. And we're going to create
a separate video row view as a reusable view. And the feed view, which has a list component, is just going to create
as many instances of the video row view as it needs for as many
videos as there are. And each video row view
will have a sync image, which will download
the thumbnail. All right, so now
we're going to have a feed view that
looks pretty good, but we have to let
the user tap on a video to view the
video itself, right? So that's why we're
going to create a video detail view
that will slide up as a sheet from the feed view when the user taps on one of
those video row views. Inside the video detail view, we're going to show at
the top the video player. And then below it,
we're going to show the description
for the video. And that data will have already. So at a high level, that's how the app is
going to look like. There is a lot to learn here. Let's dive in. Alright, let's
create our X code project. So I'm going to
choose App under IOS, and I'm going to
name this YT API app and make sure interfaces
Swift I language is Swift. We don't need any
storage options. We don't need any
tests right now. And I'm going to just
create this on my desktop, and source control
I did not check on. I'm going to change
this to the simulator, so that we can launch it in the simulator and
not on my device. Now we can get started. The first thing I want to do, let's bring up the
diagram again. We have a couple of
distinct things. I like to separate things
into folders here. We have our views,
which is home view, feed view, video detail
view, and Video view, and then we have
the data service, which is a separate helper, if you will, and then we have these
representing our data. This would be our
data model or model. Okay, so let's go
ahead and create those folders in
our Xcode project. So I'm just going to, one thing that I like to do
is to rename this. So, you know, when we name
the project, YT API app, that translates to this
bundle identifier, Y T API app. But the entry point, they
always add app at the end, so one easy way you can do is to right
click and refactor, and you can change it
all in the same place. You might want to do
something like that. Maybe we'll just call
it YouTube API app. That renamed it in a bunch
of different places. You can press command B to just make sure
that it still builds. Let's create the folder now.
I'm going to right click. I'm going to say new group, and let's call this Services. Then we are going to create
another group called Ves, and then going to create
another group called models. Let's Just do that. All right, so I'm just going to stub out all of the
files that we need and stubbing out just
means creating them perhaps adding
some initial code, but we're not even
going to do that. Let's just create the files, and then we'll focus on just creating all
of the scaffolding. So let's call this is
the data service, right? So we'll create that there. And let's just create
that initial struct. Then for the views, we're
going to say new file, I'm going to choose
Swift DI view. First of all, there's
the home view. But the home view is essentially like we've
got a view here. Why don't we use this
one as the home view? I'm going to drag this
into the views folder, and I'm just going to
rename this again. Refactor, rename, and
we're going to call this the home view. I didn't rename
this one. Then we also have the feed view. Remember, this one
contains the tab view. So we can new file. Swift I view, feed view. Then we're also going
to have video view. We're also going to
have video detail view. And then the home view. We're going to change
this to a tab view. The tab view is going to contain an instance
of the feed view. That's the basic
structure of our project. Let's just create
the two models now. These are going to be
swift file because they're not views.
So one is video. I going to create the st. And then we are going to create
another one for the playlist. Let's bring up the diagram for a second and double check
that we have everything. We have the home view, which
contains the tab view, contains an instance
of the feed view. The detail view is going to be coming up as a sheet
in the feed view. We've created the
video row view, which is going to be inside of a list component or a list
view, in the feed view. We have the data service we created and then the video
in the playlist models. We're ready to start implementing some of these
things in the next lesson. One thing I would recommend is if you're really trying to
learn some of this stuff, it's best to follow
along and try this out on your own
computer or laptop. Just open X code, start the project, and
follow along best you can. You can always download the
project if you get stuck. I'll leave the link in
the description below to download the project. All right. Now that we have
our Xcode project and all of the views
and models roughed in, we can start on
our data service, and we're going to do
that in the next video. I'll see you there.
4. Lesson 04: Sending the API Request: Lesson, we're going
to connect to the YouTube data EPI
to retrieve data. And guess what?
Because we've done this already in a demo project, this should be pretty
straightforward. The only difference
is that this time, we're going to store
the APIK securely. Let's dive right
in. First, let's review the end point that we're going to hit with our app. So on the YouTube data API, and I'll link to this
document below in case you lost the
reference to it. Going to be hitting this
endpoint play list items. Essentially, we want
to list out all of the videos for a
certain play list. Now, this is the URL, and it's going to be a
get type of request, and the required parameters, so this is what we must specify. Is going to be one of these. What level of detail
do you want for the video items that get
returned in the response? And through my testing
in building this demo, I've come to the conclusion that snippet is what you need. Now, it doesn't exactly tell you what is included
in each of these. Maybe there's additional
documentation you can search up somewhere. What you can do is in the previous lesson when we
tested out hitting the API. You can just try out all of
these parameters and see what you get back and
see what you need. Now, what you should be
targeting is getting back as little data
as possible while still satisfying
what you need to do because you never want to return more data because that
takes more bandwidth, it takes more time and why
would you just do that? Snippet is what we
need. It's going to contain the
title description, the video image URLs, and that's pretty much
all we need to be honest. Now, according to
this documentation, this is the only
required parameter. However, we still need to
specify the play list ID. Otherwise, what videos
are we going to get back. We need to tell YouTube, this is the play list that I want to get the
videos back for. This is what threw me
off in the beginning. I thought I would put the
playlist ID in there, but no, you put in there. That is the end point
we're going to hit. Now, in terms of the APIKey
that we need to pass in, You should have signed up
for this back in lesson one. If you haven't, just go back to Lesson one and walk
through that process and you can sign up for your own API K. Now we're going to jump into X code and see how we can
securely store this API K. First, I want to talk
about what storing your API K securely even
means because there are so many different ways to do it and there are varying
degrees of effectiveness. First, let's talk about
not securing the APIK, which is what we did when
we were demoing the API. Right in the previous lesson. So we hard coded the APIK
directly in the X code project, and that's bad because
you may accidentally share your project with someone or put it on source control. So if you're not familiar with source control like GitHub, it is a way for a
team to collaborate, multiple people to work
on the same code base. So if it gets on source control, especially if it's an
open source project or who knows who
has access to it? Your key is right there, and anybody can take
it and abuse it. So that's what you do not want. Now, one level of
sophistication or protection is by putting that API key in
an external file. You do not include it directly
in the Xcode project, but it sits in a different file, and then you have
your Xcode project, read the key from that file. This way, when you put
your project onto GitHub, as you can see in this diagram, the key doesn't
go along with it. The key stays in that
file on your computer, and then you have
to manually share that external file with the
key to whoever needs access, or that person gets their
own API Key and puts it in the config file and combines
it with the X code project. Now, the problem with
these two methods is that ultimately your X code project
still needs the API Key. And the reason for that is because we are
making the network calls to the API directly
from our project or our app. Our project needs
the key in order to access and authenticate against that API. There's
no way around this. Your EXCO project needs
to know about the key. If you think about
the App store, when your app is
downloaded, right, that package that is downloaded has everything it needs to work, including the API key, because ultimately your app is going to be using the API key to connect to any APIs which
your phone or your app uses. So it's still if someone tries hard enough and they know what
they're doing, probably can extract the
key out from that package. Ultimately, the most secure
way to do this would be to not even make the API
calls from your app. You would set up your own API, and your app would make
requests to your API, and it's your API
that has the APIK, that then makes access
to the third party API. In this example, that
would be the YouTube API. Then it would get
the data back from the YouTube API and then return that data
back to the app. It's almost like a middleman, which has access to the key. Then that way, the client, which is your app, will never see the key. Then what you can
do is you can have that app have its own
user account system that the user needs to sign
up for and authenticate himself or herself in order
to even hit your API. You can see how far
you can take this, it really depends, I think, to me, it depends how many
people are using your app. And how critical it is that this API Key never
fall into the wrong hands. At the very least, we
should put the API Key in an external file and not inside hard coded
in the project. This is just a good practice
as you're building your app. Now, in terms of setting
up your own software and having your app never
use the API Key to me, that is a later stage thing. Let's say your app
picks up traction, and there's lots of users
using it gets on the news, and they You think there may be a risk that someone
could target your app, maybe competition or
whatever it may be to target your app to try to bring it down because your
business has taken off. I think that's a good
problem to have, and then you would
then think about, how can I make my app
more secure and then go through this process of
setting up your own API. I wanted to go through all
of that so that you can get an understanding of what it
means to secure your API Key. In this lesson, I'm
going to show you how to put your API Key in
an external files. Here are the steps we're
going to go through. We're going to create
a config file in our X code project and we're
going to add the key to it. We're going to set the project
to use this config file, and we're going to define
a special variable in our P list to reference
that API Key. And we're not going to
do steps four and five because we're not dealing with source control in this project. But steps four and five, they are the steps
you want to do if you are putting this project
into source control because the G ignore file lists all the files that should not be put
on source control. It should not be uploaded
to Git Hub, essentially. Steps four and five, those are things that you definitely
want to do if you're putting this project into
source control or GitHub, and you're working on team. If you're curious about
how those are done, I would just Google how
to use a G ignore file, and it's literally just
listing your config file like the file name inside
that G ignore file, which is essentially
just the text file. And you include that G ignore file with your X code project. And then when you push your
project onto source control, it's going to read
that Git ignore file and take note of all the files
which it should exclude, and it will not put those
files into source control. Now let's dive into
our Xcode project and do steps one,
two, and three. Here's our X code project. Let's start by adding
that external file. This is going to be a
configuration file. Let's right click on this
main folder here, new file. At the top right corner, you'll see a filter box type in configuration,
just configure. This is the file that we want in configuration settings file. Now, the important thing to
note here is that you do not want to include it as
part of the target here. You make sure that's
unchecked and then create because you don't
want to include it. Right? Now, you type in API, underscore key in all caps, and notice this is not
a variable or constant. We don't put any swift
keywords in front of it. This is more of
like a text file. Now equals, and we are going
to bring up our API key. There it is. I'm
going to copy it, and I'm going to paste it
in there and save the file. Next, we are going to configure
our X code project to use this configuration file by
tapping on the root node here, tapping on project, and
under configurations here, you can see there's
no configuration set. There are two different types of builds that we can
create when we are developing and we're testing in the simulator or on our devices, it's what's called
a debug build. A release build is when
you create a build specifically to deploy or
send to the app store. And that doesn't contain all of the extra stuff that's only used in the development
phase of the app, such as the Bug symbols
and things like that. Anyways, for both of these, D Bug and release build, we are going to set it
to use config like that. Okay. Now, the third and
final step before we can test this is to go under
targets here. We're going to go into info. This is our P list, and we
are going to create a key that we can use to reference that value in the config file. So at the bottom, hit plus, and then you're going to
type in and all capitals AP, underscore capital K E y. Press Enter, and the type
is going to be string. I don't know why it
was a lower case P because I think there was
some auto correct funkiness. Let's correct that and
change that to capital P. And then as for the value, this is going to be a dynamic
variable or reference, and it's going to refer to
the API key in the Kfig file. So what we're going to do inside our Swift code right here is we are going to go into this P list and grab the value for this key. And the value for this key is actually pointing
to this Kfig file, which we are not going
to include as part of the project when it gets put into source control
and all that stuff. This is our external file, like we talked about before.
Let's test this out. We're going to go
into the home view, and we're going
to say on a peer. We are just going to print out the API key, see if
we can reference it. The way we reference that
info dot P list is by saying bundle main
info dictionary, that's our info P list. This is optional because
it may return NL. If it can find it, then we are going to
search for the key. And we are going to try to retrieve the value
because it has no idea of what the value is. We know it's a string,
it's a type of string, so we're going to try to
turn it into a string. And this is just try. If it can't, then it'll
probably be empty or nil. We could provide
a default value. So yeah, if it can't
find anything, let's print can't find it. Okay, for our own debugging. Okay let's try this out. We are going to run
this in the simulator, and so it's running right now. And we should see
our API key print out there if everything
is according to plan. All right. Perfect. It works. This is referencing the info
list, looking for this key, and the value for this key is referencing the config
file API key right here. Perfect. Now let's move on to implementing
the data service, where we're going to
send off the API call to the YouTube API and
to retrieve the data. So in the data service
file at the top, let's declare our key
as a private constant. And we're going to
call this the API key. And we're going to handle this just like I
showed you before, bundle dot main dot
info dictionary, and we're going to
try to look for API Underscore key as string. Now I'm not going to give it a value like this if it can't retrieve it because I do want
it to be NL in that way we can detect if the API
K is present or not. Next, we are going to create a new function called G videos, and it is going to return
an array of videos. Essentially, I wanted to give back all of the videos
for a given playlist. We are going to make this
an asynchronous function, and I will explain
what that means when it comes time
that we call this, and I'll explain what the
Async and await keywords mean. For now, why don't we just
return and empty video array? Here we're going to
implement that API call. First, check if
API key is there, and then we are going
to create the URL, create the request,
and we're going to send the request and
then finally parse it. This really helps that we did this inside a demo back
in lesson two, right? So we've tested that this
works, we know it works. So we're going to say guard API Key not equal
NL else return. U We can return an
empty video list because it can't get anything. Idally, what you'd want to do is probably show an error message
or something so you can return something as such and then capture it and
display it to the UI. But by doing what
we're doing here, you're returning no videos. So the user doesn't know if there's actually no videos in that play list or if
something went wrong. But clearly something went wrong because we can't get
the APIK, right? Okay. Coming down here, we're going to create the URL. And before we create
the url actually, we're going to create it
off of a string, right? And that url string is going
to look something like this. First, let's go back
to the documentation. So that is right here. And as I mentioned in the
previous lesson, we are using this end
point right here. We're going to retrieve
all of the play list items given a play list. I'm just going to put
that right there. I'm going to hard code
that URL right here, and we're going to
add the parameters. One of the required parameters is this one part I mentioned
before in lesson three. Why picked snippet because
it contains what we need. Then the other thing
we want to specify is which play list do we want to target to retrieve all
of the videos for. Okay. So the way
you find this is, I'm going to choose
my own playlist. You can choose whatever
playlist you'd like. But if you go to someone's channel and you go to playlist, you'll see all of
the playlists here. I'm going to click on this
one, your full playlist. And it's just this
ID right here. If you double click it, you'll
highlight the whole thing. I'm going to copy that, and I'm going to paste
that in there. And the last thing you
have to add is the key. So we're going to
say key is equal to, and we will just insert
that right here, API key. And we've already checked
that it's not nail, so we're going to just
force and wrap it here. Now we can create the URL
instance off of that string, now we can create the request. Let's do that URL request, and we're going to do it
off of this one right here. We're going to pass in the URL. Actually, this one returns an
optional. This could be NL. We're going to say,
if URL equals URL, just to check that it's not NL. We're going to put
all of this code in here that only executes if we're successfully able
to create a URL instance, then we're going to
do that in there. Then sending off the request is a matter of using session. If we say, let's create another constant right here just to make things more clear. URL session shared. This is just breaking
things up so it's easier for
you to understand. And if If you look at this one, which is what we're
going to use, data retrieves the data
for a given URL request, which we have created up here, and it is both an
asynchronous method and it also potentially
throws errors. So we have to address
both of those things. The third thing I want
you to notice with this method is what
it returns to you. It returns a tuple. So it has two pieces of data. It has data, which is the actual data that is
returned by the API, and a response object, which you can take a
look at for any errors or the status code
and things like that. So that is the actual response, and that is the data separated
into its own parameter. We're going to also handle that. But first, let's do
things one at a time. Let's handle the T throws part, and then we're going
to do Async and then we're going to handle the
data that gets returned. Throws. Let's pass
in the request. If calling a method may throw an error,
we have to catch it, and the mechanism in Swift to do that is to it looks like this. You do something that may
potentially throw errors, which is this line of code. You have to put a tri
keyword in front of it, so we're going to
try to do this. Then you have to also
have a catch block. This displays, or you can handle any errors that get
thrown if it gets thrown. We're just going
to print it out. This we'll reference the
error that gets thrown out. Next, let's handle the fact that this is an
asynchronous method. In order to call the
asynchronous method, which means that
it gets called in a background thread or
a background worker. So imagine yourself tasking
someone else to do the work, like you're giving someone
else a task and have that person go and do the task and come back to
you when it's done. You have to put
the await keyword, which means that you are going
to wait for that person, that background worker,
to come back with the completed task
before you continue and execute the rest of the
lines of code below it. So that's what's
going to happen here. Now, I do want to explain, even though it waits for
the background worker to do that task and comes back before we execute the
next lines of code, it is still good
because while we are waiting for that background
task to come back, we can handle any sort
of user interaction, and we can also do
some other things before we execute the
next lines of code. It's just that the await
keyword tells the system, do not run lines three and below until that
background worker comes back. And for things like this, you
do want to send it off as a background task because if
you have the main thread, which is the main thread
that is executing this code, go and do that work, there will be no worker to handle all of the user
interaction and stuff. And so it'll look
like it's frozen. So that's kind of
the gist of it. With any sort of tasks like network requests or
database queries, and you'll see when we do the thumbnail downloading
for the images. We're also going to send that as a background worker
to go and do that. So that's using the Async
and await keywords. The fact that this is in
asynchronous method will also come into play when we have the Feed Vew call get video, you're going to see how we
use the A weight keyword. Okay. So hopefully, that
makes sense, if not, I would recommend that you dive a little deeper into
Async and a weight. Search for some
additional tutorials on Async and a weight in Swift, so you can understand it in a little more detail more than we have time
to cover right now. So we've handled the fact
that it throws an error. We've handled the fact that
it's an asynchronous method, meaning background worker
is going to go execute it. Now we have to handle the
data that comes back, and it's a tuple, right? So we are going to declare our own tuple to
track that data. We're going to declare
a tuple constant. We're going to say
data and response. You'll notice that
this format looks like what we saw
this method returns. We're going to say equals this. So if no errors get thrown, when the background
worker comes back, it's going to assign the data to this and it's going to
assign the response to this. And then from here, we
can parse the data. Now, before we actually
parse the data, let's try sending this
request off and taking a look at it inside Proximan to make sure that
it's happening. So what we're going to do first, we have to actually
fire off this request. So inside the feed
view, right here, why don't we say
on not on a here, but we're going to use task. Let me explain what that is. The task is a modifier that lets you execute a
block of asynchronous code. Let me put that into
Layman's terms. When the feed view appears, it is going to run
this code inside this task block as a
background worker. We are going to say
we're going to create a property up here
to store the videos, and this is going to
be a state property. Let me explain what
that means as well. It's going to be an empty
array in the beginning. In case you haven't watched my eight day beginner
series where I explained what state
properties are. It's essentially when
this value changes, we want the UI to refresh. This starts off as an empty
array, there are no videos. But when we send
off the task from the data service to retrieve the videos
and it comes back, and then it puts the video
instances into this array. We want the user interface to refresh and
show those videos. That's why this is
a state property. Let's fire off this task. We are going to create a new data service instance and I'm just going to
chain it like this. I'm going to call get video. That should be an S.
We'll change that. This should be get videos and Notice that it's an
asynchronous method. And it returns a list of videos. So Asynchronous means
we're going to have to send it off as
a background task. We're going to have to
wait for that to come back before executing
the code below it. We're going to say let
videos equals that, the return to list of videos. Let's call this. Let's
call it returned videos. Then we are going to assign the return videos to our
state property here. Self thought videos
equals returned videos. We can shorten this definitely, but I wanted to break
this up into two lines to explain to you the fact
that this line of code will not execute until this has gone and come back with the data because of
this await keyword. While the main worker is waiting for the background worker to retrieve the data, it can still handle user interaction and other
things that it needs to do. That's what's so great
about ACN can await. We can shorten this by
just putting this like this and removing the
need for this even. All right, but I thought
writing it like that would explain the await keyword
a little bit better. So with the way
we've set it up now, if we run this in the simulator, it it should execute this and then send off
the network request. And if our API is correct and our request is
structured properly, we should get a response. So let's go ahead and
open up Proximan. Let's go ahead and take a
look, see this in action. I'm going to first run this in the simulator so that
it'll show up on our list. There it is. I'm going
to pin this one to the top and I am going
to have to resend it. Hello World, send it. All right. The status code is green, it should be a 200, 200, and we get the
data back here. You can see the root element
contains an array of items. This root element,
we represent it with our playlist model. We're going to model
it off of that. Then as for the items, these are the individual videos, which we are representing
with instances of video. Obviously, we haven't
filled it out yet, but that's what
we're going to do. If you open one of these videos, you're going to see that
it has the snippet, which is what we asked
for in the API request, and it contains the
thumbnails, the title, the description,
and the video ID is also something that we need. So inside resource ID,
here's the video ID. So those are all the
details we need. And inside thumbnails. You can see that has different
sizes of thumbnails. Each size has a different URL. All right, I think
we're halfway there. Now with the request being sent out and the
data being returned, all we need to do is
parse that JSON data into video instances so
that we can display it. And we're going to do
that in the next lesson. I'll see you there.
5. Lesson 05: Parsing the JSON data into Videos: In this lesson, we're
going to turn that JSON data returned
by the API into video instances
so we can display it in our feed view.
Let's dibrt in. The first step is to fill out the properties of
our data models according to the
response that we get from the Tube data API. Let's take a look
again at Pxy Man, and this tool is really helpful, especially because you can just send the
request and look at the response and
get this tree view and then you can go
through it like this. Sometimes the documentation
will have the response, so this is the YouTube data API. I know the API Epler if you use this and you
try out the request, you're going to be able
to see the response. Here, this gives you an idea. Yeah. So if you don't want to use Proxy
Man to look at it, you can look at this as well. This would be the playlist
object or instance, and this would be the items. Each item is a video. If you click on
that, you can see, these are the properties
of the video. Actually, let's use
this because the text is bigger than we have
here in Proxy Man. We're going to start
with the video itself. So we're going to add
the decodable protocol, and this allows us to
turn the JSon data into instances of video
using JSon decoder. So let's bring up the
API documentation. What I'm looking at right
now is a single video. So we can see that it has
an ID, which is a string, and this will be helpful for us because we want to put
these video instances inside a Swift DUI
list and it needs to be able to identify
between different videos. So We are going to
pick and choose the properties that we want
to parse, essentially. So there's going
to be string ID. Then there is going to be a snippet and inside is
going to be a title. It's going to be a description. Both of these we need,
and those are strings. And then there's also
going to be thumbnails. Let's first focus on
title and description. Again, this is a
snippet property, and the snippet itself, you can see these
curly brackets, that represents a
different instance or struct or object, whatever
you want to call it. All of it is representing
the same thing. We're going to say snippet is going to be let's give
me a type of snippet. I'm going to make this optional
in case it doesn't exist. Yeah, Snippet and not snippets. I can make sure that the
property is the same, and I'm going to
create another struct in here called snippet, and it too is going
to be decodable. Inside the snippet is where I would put
title and description. O. I mean, all videos should
have a title and description, but just in case they don't, you can make them optional. For now, I won't, let's
just see what happens. Then inside the snippet,
we have thumbnails. What else do we need here? We need the video ID. Let's deal with that
before thumbnails because there's quite a bit
in here with thumbnails. Let's do resource ID. I'm going to spell it with
lower case like this. Let's do that. Then here, I'm going to create
another struct called resource ID that is decodable. The resource ID, well, the only one I'm
really interested in is video ID,
and it's a string. I know that all videos
must have a video ID. Let's deal with thumbnails. Was it thumbnails with an S? This was inside the snippet. T thumbnails with an S
yeah then this itself is its own thing. We
have to define that. Let's call this thumbnails. Let's create another
stru called thumbnails, and this is going to
be decodable as well. What do I need in
here? Let's key. Let's take a look at proximan here to look at a real response. We've got the snippet here, and then we've got then thumbnails right here.
Let's open this up. And then there are
several different ones, standard medium
default high max is. So you can try out
these different ones. These are all
different file sizes. You probably
wouldn't want to get this one like this is
the biggest one unless You're showing it
on an iPad maybe, or you want it super clear. When I was building my demo, I was pretty happy with medium. So that's what I'm
going to go with. Actually, medium is
almost the smallest one. Default is pretty small. So this is almost
double that size. But I remember why I e medium is because the
aspect ratio is different. So you can see that
these are about Yeah, the aspect ratio was
a little different. Some of these look more square, and some of them look more like a wide screen
type of thing. So I figured out after
trying them out, that medium was the one
that displayed nicely, so that's what I chose. Yeah. So I'm going
to say far medium. And what's the type? The type
itself is another object. So I'm going to have to
create something for that just to how is
these three properties. This one is a string. This one is an int, and this one is an int as well. So let's create a
strut thumbnail size. This is decodable
to what is it URL. Like that height deal. Then this one will be
just thumbnail size. Do I have everything I need? I have the thumbnail image, URL, I have the video ID. This is for the video player. Then I have the title and the description. I
think this is it. Perfect. Then going back out. This is a single video
going back one step. This is the play list. The play list has and items, which is an array of
those video instances. If I go to playlist, let's make sure that
this is also decodable and we want items. Like that. Let's also, we need
to add identifiable, which allows us to use an array of this inside
the Swift DUI list, and we have the idea ready for
the identifiable protocol, because that's what
that requires. And I think we're okay now.
Let's try to parse it. Let's go into the data service, and continue parsing the data. We are going to
create a JS decoder. C. And then we're going to say decode decode a
certain type from. We're going to decode
the data from here, and we are going to decode it into an instance of play list. We're passing in the
play list as a type, and so we have to add dot self. This is how you specify a type. Oh, I forgot to point out that this decode method
can throw errors. It's asking you to do try. A We can put the try right here since it's already in
a D block. That's perfect. We don't have to do another one, unless you want to specifically handle that error
versus this error. I'm sure you can differentiate in here though
when you catch it. Let's capture the result
of this decoding. Let play list equals that. Then as you know, our play list
instance has items, which are the videos. This is what we are
going to try to return. Because remember this
method right here returns scenario videos. All right. Let's see how this works. Let us go back to our views and double check
what we're doing here. I'm going to set a break point right here by tapping here, which is going to
pause the execution. Let's add a little bit
more before we run this. That way we can visually see
something in the simulator. Let's use a Swift DUI list
and we are going to pass in the videos Because the video
strut is identifiable, then that is all good. That means we can
use it in this list, and then we are going
to i for each video. Let's just di the snippet title. If that is NL, just say title. Let me just do that. Let's see if we can
see anything come up. Oh, it was so fast. But we could see the rep
sorry the request to go out, the response comes
back with five items, and sure enough, we see
five items right here. Now, I expected to see more
because our playlist actually has like eight videos or nine videos in here,
ten videos, actually. Let me take a look at here. I think by default, Yeah, the default value for
Max results is five. So this is something that
you'll want to set as well. Let's change that in
our data service. What was that Max results Capital R. I'm going to
add that right here. Max results equals
20, let's say. This it's telling us that we
never checked the response, so we can just ignore that
by adding an underscore. We don't have to name that.
A. Let's run it again. Happened so fast there.
We have everything. What we did here today by parsing the JSO
through looking at the response and then mapping these key value pairs and creating these properties
in our data model. This is something that
is very common to do. So it's best to
get familiar with this process if you want to work with different
APIs in the future. All right. Now that we
have the video instances showing up in the feed view, the hard part is done,
believe it or not. Now, all we have to do is show the thumbnail images
in the feed view, and we're going to do
that in the next lesson. I'll see you there.
6. Lesson 06: Retrieving Video Thumbnails and Styling: The last lesson, we parse
the JSON data returned by the YouTube API into video instances that we're
displaying in our feed view. Now, the problem
is we don't have any video thumbnails to show, and we're going to fix
that in this lesson. Let's do it. Here's what we have so far with
our feed view. Let's clean this up a bit. We're going to go
into feed view, and the first thing
I'm going to do is change the style of the list list style to plane. And then we're also going to
remove the scroll indicator. So let's to that
scroll indicators. We're going to hide that. And it should already
look a little better. Perfect. Then we are going to remove these separators between each item because
these are going to be images, thumbnails. In the text here,
I'm going to say row separator
visibility is hidden. The other thing is, remember how we have a tab view
in the home view. Let's add that tab
icon right there. In home view, we can
remove this on a peer, display our API Key
and add a tab item. In here, we are going
to put an image, and this is going to be an icon, SF symbols, and we are
going to use stack. This one, play square stack. Let's see if I can
put it right there. I just did the
whole thing for me. Then the text is
going to be feed. That already is going
to look a lot better. Now let's take a
look at displaying those images using
our video row view. Instead of displaying
a text with the title, we are going to want to create instances of video row view. But we need to pass the video
into the video row view. Otherwise, this view won't
have anything to work with. Why don't we create a property here that will need
to get passed in. And for this purpose, maybe we'll just do that. From, I don't want to
create all of that. I'm just going to ax
the preview itself. Okay. And let's go
back to Feed view, and we are going to
pass it in here. See, now it requires that. I'm going to just pass in the video that it's
trying to display. Now, in the video row view, let's display the image. Now, remember, we do have
the URL to thumbnail image. It is inside video dot
snippet thumbnails dot medium do URL. This is a string. We need to essentially
hit this URL to download the image data and then display that image data
inside a SwiftUI image. Luckily, for us, SwiftUI makes this really easy
using a sync image, where you just pass in a URL, and it's going to do
that asynchronously. It's going to send a background
worker to go to that URL, fetch the image
data, come back and then display it inside an image. We're going to use this
one because it gives us a reference to the
Swift UI image view, which allows us to add some additional modifiers to it if we want to tweak the corners, we want to tweak the aspect
ratio, we can do that. Placeholder allows you
to specify what to show while that
background worker is grabbing the image data. We're going to show a spinner. Obviously, URL is where
should it go retrieve that. Now, because all of
these are optional, we may not have an image URL, so we have to check
for that first. So we're going to say,
if let URL equals, and we're going to try to create a URL instance off
of that string. If it is able to create this, then we are going
to pass this into the Async image call or
sorry view as a parameter. That's where we're
going to pass that. What is the string again? Well, it is video snippet
thumbnails, medium URL. If it doesn't exist, then it doesn't exist. Then we can't show an image. So what do we have to do
here to provide optional Default when the
optional contains Nil. Be it must be a string. So yes, if any of this
part isn't a URL. If it cannot create this string, then we're just going to put an empty string and
try to create a URL, and it's going to fail, and it's going to not do any
of the stuff in here. Now let's set our Async image. We're going to use this
one right here, as I said, and we're going to pass in
the URL that was created, and then we are going
to double click here. This is the. This
is the reference to the image that will get displayed once the
data comes back. This is the image
that is displayed. This placeholder, we have another handy swift UI view
we can use is progress view, which is just going
to be a spinner. Regarding this image right here, we definitely want to add a
couple of modifiers to it, for example, resizable, so
that it can scale up or down, and we want to maintain
the aspect ratio. So the one that I like to use, depends on the circumstances. Why don't we just
try fill for now? And we'll see what happens. Let's also give it a little
bit of a rounded corner. We're going to do clip shape. We're going to say
rounded rectangle corner radius is ten. Now let's see if this works. We're going to go back to
feed, just double check. It's going to create instances of video review and
pass in the video, and then this should
download the images. We are not showing the
titles here actually. All right? Well, that
was pretty easy. You have to admit just
like that, we have this. If you wanted to
display the titles, you would you can
either display it, the titles don't depend
on the image, right? So you could put
all of this inside a V stack and then put the
title underneath, for example. So we could try to do that here. And this would be the title. Video title, and then we
can even make it bold. Is it not title? Oh,
sorry, snip it title. If it doesn't exist, we'll show empty string. We can line, we can add
some padding, for example. Leading, and then you could add just some padding overall or just maybe just
to the vertical. Okay. The corners are a little bit too rounded
for my liking. So we'll just do five. All right. And that's how
easy it is to do that. Alright, our feed view
is looking pretty good. All we need to do is
allow the user to tap on the thumbnail
to watch the video. That's what we're gonna
do in the next lesson. I'll see you there.
7. Lesson 07: Video Player and Video Detail View: The last lesson, we
finished the feed view. In this lesson, we're going
to allow the user to tap on the thumbnail to show up the detail view and
to watch the video. Let's dive right in. So we already stubbed out
the video detail view. Let's start by triggering
this and showing this as a sheet when the user taps on a video. How are
we going to do this? So there is a sheet that
you can bind to a property. Up here that you can define, which we are going to
define as selected video. When the user taps
on a video row, we're going to capture
that gesture and set that selected video property, which is then going to
trigger this sheet, and then content is what you
want to show on that sheet. Let's choose that. Let's create this state property up here
and call it selected video. This is going to
be Nil at first. We're going to bind to
the selected video. And as for the content, content. This parameter stores
the value of that, which is the selected video. Here we're going to show
the video detail view. Okay. Let's capture the
tap gesture on this. So on tap gesture, we are going to set the
selected video equals V. And let's see if this works. Perfect. Now the next step, let us pass the video
details into the sheet. We're going to do that by in
the video detail view here. Let's accept a video. Again, I'm going to
blow away the preview. Then in the feed view, we are going to now pass in V, which is the selected video. Now let's configure
this a little bit. We're going to have a
sheet to where the top is the video player and
the bottom bit is the title in description. So we're going to need
a V stack setup here and let's set the alignment to leading because that
makes sense for the text. We're going to have
our video player here, which we're going to get to, and we're going to have the
title and description here. I want this scrollable in
case the content is a lot. Inside the scroll V, I'm going
to create another V stack. This one should be
alignment left as well. I don't know if I need
the first one then. In here, I want to put the
title in the description. This is going to have
a piece of text, and it's going to be
video snippet title. If that doesn't exist, I'll put empty string, and I'm going to want to
make this one headline font, and I'll bold it as well. I'll add some padding to the bottom just to give
it a little bit of space. Instead of this, I
can actually add the spacing here because there's only two elements in here. I'm going to add the
spacing of 30 right there. I don't have to put
the padding there, and then I'm going to
put the description. This is going to be video
snippet description instead. Let's see how this looks.
I've got the title. I've got the description, but I need to add some padding. I'm going to add the
padding to the scroll view. Should I do only horizontal? No, probably I'll add
it in all directions. All right. That looks
a little better. Oh, scroll indicator. Let's get rid of that too. Scroll indicator hidden. Okay. All right. No scroll indicators. This looks good. Now, I do want to spend
a moment and talk about what options we
have when it comes to displaying YouTube
videos in our app. Now, we could use a
web view and display an embedded YouTube video. But they also have a
client library for us to use how to embed YouTube videos in IOS applications with
the YouTube Helper library. Essentially, they're
doing the same thing, but they're making it because they're using an i frame player. They're making it a
little easier for you, but this uses objective C. So
this is an option as well, which is a little easier than
showing your own web view and trying to put
the player like the actual web embed
code in there. The third option
which I explored was to use Tube Player Kit. And this library worked
really well with Swift Juan was really easy to use and honestly
saved a lot of time. So I didn't even consider
the other options, and this is what we're going
to be using with this demo. So this library from Sven seems pretty active,
as you can see here, last issue was
closed two days ago, and the last poll request was
merged about a month ago. As with any third party
libraries when you use them, you're creating a dependency
from your project. To depend on third party code. And the risk is that that third party code
becomes out of date, it's not maintained,
and it becomes buggy, and then that affects your app. So there is a risk reward
consideration here. On one hand, you could
roll your own and even depending on this library
itself is third party code. I mean rolling your own
would be the best thing, but that would take the most effort and
take the most time. Versus using a third
party library, saves you time of
time and you have to gauge whether or not
it's worth the risk. In this case, this was really easy to use and it worked
beautifully in Swift UI. Seems active, I think
the risk is low, so that's why I
decided to use this. Let's dive in and integrate this Tube player kit
into our project. Let's hit this blue button
saying, use this package, and we can use Swift
Package Manager to directly import
it into our project. Now, you know how in Lesson two, we created a demo
project to test out sending network requests and receiving responses from
the YouTube data API. This would be a perfect
opportunity to do the same. Whenever I'm trying
something new, start a new ExCo
project, test it out, if it works, put it
into your main project. I've done that So I'm not
going to go through that again with you and then spend
an extra lesson doing that. What I'm going to do is just directly put it into
my main project. But in the future,
when you're working on your own stuff, I'm
just letting you know, you might want to consider not, especially because we're not
using source control here. If you are playing
around with your code, you're importing things
and you mess something up, it's hard to roll back, right? So definitely test things out in a different project first. That said, Let's import this
directly into our thing. So go to file Ad
package dependencies, and I copied that URL. We're going to just
enter it right there, and there it is,
UTub player Kit. You can go ahead
and hit Ad package. And while that's going
on, let's come back here and scroll down and take a
look at how we use this thing. So Looking at this code snippet, you import UT player Kit first, and then you create
the Tube player view. And it looks like you just pass in the URL just like that. So as an initial test, why don't we just
do exactly this? We're going to copy that. We're going to go back here. Let's add package. There it is. In the video detail view, we're going to import
you two player kit, and then under video player, we're just going to
plop it in right there. And we are going to run this
now and see what happens. It's good, it's showing a video, but notice that the frame is larger than the
space that we have. It plays. That's great. The controls are there. The video itself it doesn't look wider than
the space that we have. It looks like it's
fitting the width. However, it does look
like there's a lot of black space at the top and the bottom because
when you load this up, It takes up so much height. We might have to set the width just set the frame for this so that it fits in the
space that we have. Also, we don't want to be
displaying this video. Why don't we try inserting our own ID into
here dynamically? This would be snip it. But as you can see,
there's something wrong here because as
I'm trying to do this, it is not working. The autocomplete
is not showing up. So we actually cannot
do it this way. We can't just insert a wild card into a
parameter like this. Why don't we take a look at some other methods
that we can use this and perhaps that
would work for us? Okay. So this is ultimately what I
ended up using right here. So you can configure the
YouTube player like this first, where you can actually pass
in a dynamic video ID, and then you then you could
use that video player view. So let's copy this. Is of, let's configure it here. Then we are going to
add our ID there. This would be video set
resource ID video ID. If that happens to be Nil, we'll pass an empty string. I don't want it to autoplay, so I'm going to
set that to false. Then with this configuration, if you go back to this page, you can see that you can just
pass in this configuration into the the YouTube
player view. Yeah, so it looks
something like this. This is what we did. We configured
something, and then we can pass it into the YouTube
player view like that. I forgot exactly
the snippet of code when I was looking through this. But, if you take the time
to read through that, there's a lot more cool
stuff that I can do. But I'll just show you
how to do it here. When you create the
configuration like that, this is Tube player, you can
even call it like, Okay. Instead of specifying
the URL right here, we can actually pass
in the Tube player, the thing that we
created up here. I'm going to run it.
And this allows us to specify that dynamic
ID. There's my video. St the frame isn't
working properly, right? But it is displaying the correct
video and it is working. Perfect. Now we need to
figure out how we can set this frame for this video player so that it fits in the space. You would just go frame and you would set width and height. The problem is that we
need to know what that is. Using geometry reader, we can take a look at how
much width we have. And we are essentially going to create the
geometry reader up here. And we are going to
cut the whole V stack, and we're going to paste it
inside the geometry reader. Now because this Vtac is inside
the geometry reader here, we have access to proxy. The width is going to be
proxy dot size width, that gives us the
width of the screen. Because geometry reader,
the purpose of this is to is to read the
size information. So this parameter gives us
a reference to the sizes. Now that we have the width, we can make sure that
it is the proper width, but we have to set a
proper height as well. Only setting the width
is not going to work. The question is, what should
we set the height to? How do we figure that out? Well, we can express the height
as a ratio of the width. We need to figure out for these YouTube videos
that get displayed. What is the aspect ratio? One clue that we have
is if we go back to, I can open up proxy maan again. But essentially,
I want to figure out let's just comment
this out for a second. What is that ratio between
the width and the height? There are various
ways to get this. But let's take a look at this. I'm going to get the clue
from the thumbnail sizes. If we take a look at
the items and we take a look at the thumbnails, we did the medium
one, 320 by 180. If the width is 320, then what is the height? 320/180. The ratio is the width is 1.78, 78 times larger than the height. We would reverse that in order to get the height
because we have the width. We would divide 320 by
that in order to get 180. Let's see if the math works out. T 20/1 0.7 s78 gives us 180. That's how we're going
to get the height. Coming back here, if proxy geometry reader is
going to give us the width, then we could calculate the
height by taking proxy size width divided by what? Yeah, eight. Let's take a
look. So this should work. And sure enough, we have the appropriate
width and height. The cool thing was that this
would also work like this. Especially if we
ignore safe area. That's why you see
this part here. If we go back to the home view, we can say, ignore safe area. This might get it to go.
There's that padding there, so I don't want to add
that padding there. I do want the tab
view to be full. Perfect. But now we
need to add a padding to the feed view. We'll probably put it in here. Uh, Let's put the padding. Oh, probably just padding
horizontal. Okay. Alright, our YouTube player app is looking and feeling great. I hope you learned a lot, and I hope you were able
to follow along. Please check out our other
courses on the platform. Alright. Thanks for watching, and I'll see you in
the next course.