1
00:00:02,010 --> 00:00:04,750
Hi, and welcome back.

2
00:00:04,750 --> 00:00:08,060
This video is recorded a little bit after

3
00:00:08,060 --> 00:00:09,270
the rest of the course,

4
00:00:09,270 --> 00:00:12,070
so you may see a little difference

5
00:00:12,070 --> 00:00:14,240
between the other videos in the course

6
00:00:14,240 --> 00:00:15,870
and this section.

7
00:00:15,870 --> 00:00:17,850
Please bear with me while I explain then

8
00:00:17,850 --> 00:00:20,433
and also while I bring you up to speed.

9
00:00:21,310 --> 00:00:25,380
So what we've got here is Visual Studio Code.

10
00:00:25,380 --> 00:00:27,300
This is changed from Atom.

11
00:00:27,300 --> 00:00:29,480
So in the rest of the course we were using Atom.

12
00:00:29,480 --> 00:00:30,800
Now I'm using Visual Studio Code

13
00:00:30,800 --> 00:00:32,690
just because a few months have passed.

14
00:00:32,690 --> 00:00:34,380
I've come to the conclusion

15
00:00:34,380 --> 00:00:36,720
that Visual Studio Code is a bit better,

16
00:00:36,720 --> 00:00:38,890
a bit nicer to work with,

17
00:00:38,890 --> 00:00:40,020
just looks a bit nicer.

18
00:00:40,020 --> 00:00:42,850
It has more integrations with things.

19
00:00:42,850 --> 00:00:44,220
If you wanna keep using Atom,

20
00:00:44,220 --> 00:00:45,870
by all means do that.

21
00:00:45,870 --> 00:00:49,590
I'm just using Visual Studio Code now more often.

22
00:00:49,590 --> 00:00:51,363
So that's why I'm using that.

23
00:00:52,270 --> 00:00:53,970
All of the time I'm also using PyCharm.

24
00:00:53,970 --> 00:00:56,100
So still can use that if you want.

25
00:00:56,100 --> 00:00:57,513
It's also a very good tool.

26
00:00:58,680 --> 00:01:02,300
For our all intents and purposes it's gonna be the same.

27
00:01:02,300 --> 00:01:03,900
So you're not gonna notice any difference

28
00:01:03,900 --> 00:01:05,930
between the rest of the course and this one.

29
00:01:05,930 --> 00:01:07,230
Just the editor looks a little bit different,

30
00:01:07,230 --> 00:01:08,163
but that's it.

31
00:01:09,920 --> 00:01:12,370
Now, in this section

32
00:01:12,370 --> 00:01:17,160
we are going to look at Flask-JWT-Extended.

33
00:01:17,160 --> 00:01:19,440
A lot of you have asked for this section

34
00:01:19,440 --> 00:01:21,310
to be included in the course

35
00:01:21,310 --> 00:01:24,840
because it contains a key piece of functionality

36
00:01:24,840 --> 00:01:26,330
when we develop authentication

37
00:01:26,330 --> 00:01:30,253
in our REST APIs, which is token refreshing.

38
00:01:31,130 --> 00:01:35,450
Token refreshing allows you to get a new JWT

39
00:01:35,450 --> 00:01:38,120
without asking your users for their username

40
00:01:38,120 --> 00:01:39,730
and password again.

41
00:01:39,730 --> 00:01:43,490
If your JWT expires after say 10 minutes,

42
00:01:43,490 --> 00:01:45,060
every 10 minutes you have to ask your users

43
00:01:45,060 --> 00:01:46,750
for username and password

44
00:01:46,750 --> 00:01:49,440
if you don't use token refreshing.

45
00:01:49,440 --> 00:01:52,370
So we're going to look at Flask-JWT-Extended

46
00:01:52,370 --> 00:01:54,020
because it supports that,

47
00:01:54,020 --> 00:01:55,680
but, of course, I'm also going to guide you

48
00:01:55,680 --> 00:01:58,120
through using Flask-JWT-Extended

49
00:01:58,120 --> 00:02:01,120
like we have done with Flask-JWT,

50
00:02:01,120 --> 00:02:03,530
but, because you already know a bunch of stuff,

51
00:02:03,530 --> 00:02:05,530
we don't have to cover absolutely everything

52
00:02:05,530 --> 00:02:07,560
in very slow detail.

53
00:02:07,560 --> 00:02:08,950
We can go quite quickly

54
00:02:08,950 --> 00:02:11,620
because a lot of thing are very similar.

55
00:02:11,620 --> 00:02:14,130
Now this code that you see here

56
00:02:14,130 --> 00:02:15,890
is more or less exactly the same

57
00:02:15,890 --> 00:02:18,060
as the code that we had

58
00:02:18,060 --> 00:02:19,610
at the end of the last section.

59
00:02:20,650 --> 00:02:22,180
There are a couple differences,

60
00:02:22,180 --> 00:02:23,370
and I'm going to highlight them

61
00:02:23,370 --> 00:02:25,610
for you in this video.

62
00:02:25,610 --> 00:02:28,880
So please take the code that I provide

63
00:02:28,880 --> 00:02:30,570
at the start of this section.

64
00:02:30,570 --> 00:02:33,740
It's linked in the resources of this lecture.

65
00:02:33,740 --> 00:02:34,970
It's called the starter code,

66
00:02:34,970 --> 00:02:37,640
and that's the starter code for this section.

67
00:02:37,640 --> 00:02:40,100
So you can feel free to download that

68
00:02:40,100 --> 00:02:41,490
and give it a go.

69
00:02:41,490 --> 00:02:43,110
It'll be more or less the same

70
00:02:43,110 --> 00:02:44,910
as what we've already got.

71
00:02:44,910 --> 00:02:45,930
For the rest of the section

72
00:02:45,930 --> 00:02:47,810
I recommend you use this code

73
00:02:47,810 --> 00:02:50,100
as opposed to the one in the last section

74
00:02:50,100 --> 00:02:51,810
because of these minor difference

75
00:02:51,810 --> 00:02:54,050
that I'm about to tell you about.

76
00:02:54,050 --> 00:02:57,190
The first minor difference is this line here.

77
00:02:57,190 --> 00:02:59,623
App.confige PROPAGATE_EXCEPTIONS is true.

78
00:03:00,870 --> 00:03:01,880
What does this mean?

79
00:03:01,880 --> 00:03:05,020
Well, turns out when you're running your Flask app,

80
00:03:05,020 --> 00:03:08,100
if Flask-JWT raises an error,

81
00:03:08,100 --> 00:03:11,210
your Flask app is not going to see that error.

82
00:03:11,210 --> 00:03:14,280
For example, let's say Flask-JWT raises

83
00:03:14,280 --> 00:03:15,970
not authorised error,

84
00:03:15,970 --> 00:03:19,530
and it tries to return an error code 401,

85
00:03:19,530 --> 00:03:22,850
which means unauthorised in the HTTP codes.

86
00:03:22,850 --> 00:03:24,530
If you don't have this,

87
00:03:24,530 --> 00:03:26,380
your Flask app is actually just going to return

88
00:03:26,380 --> 00:03:27,700
an error code 500.

89
00:03:27,700 --> 00:03:29,620
It's going to say, sorry,

90
00:03:29,620 --> 00:03:31,030
I don't know what to do,

91
00:03:31,030 --> 00:03:33,310
so I'm just gonna give you an error.

92
00:03:33,310 --> 00:03:35,110
If you allow PROPAGATE_EXCEPTIONS,

93
00:03:35,110 --> 00:03:37,290
that means that the Flask extensions

94
00:03:37,290 --> 00:03:42,290
like Flask-JWT can raise their own exceptions

95
00:03:42,330 --> 00:03:44,690
and return their own codes

96
00:03:44,690 --> 00:03:46,530
and their own message to the user,

97
00:03:46,530 --> 00:03:47,970
so you would be then returning

98
00:03:47,970 --> 00:03:51,920
a specific error that Flask-JWT has told you

99
00:03:51,920 --> 00:03:54,470
or told your app to return.

100
00:03:54,470 --> 00:03:57,150
So that lets your exception return

101
00:03:57,150 --> 00:03:58,680
their own custom errors,

102
00:03:58,680 --> 00:04:00,783
which can be really handy at times.

103
00:04:02,320 --> 00:04:06,210
Now, there are a couple other small changes.

104
00:04:06,210 --> 00:04:08,780
For example, here I'm going to the item resource,

105
00:04:08,780 --> 00:04:10,590
and you'll see that most things

106
00:04:10,590 --> 00:04:12,220
are more or less the same.

107
00:04:12,220 --> 00:04:13,900
There are a couple of differences here.

108
00:04:13,900 --> 00:04:15,610
Previously in the last code

109
00:04:15,610 --> 00:04:20,083
we had them ItemModel passing in data,

110
00:04:21,010 --> 00:04:23,030
price like that.

111
00:04:23,030 --> 00:04:27,950
Now we are passing in the unpacked data,

112
00:04:27,950 --> 00:04:31,013
which means it contains everything in a dictionary,

113
00:04:32,220 --> 00:04:33,900
store ID and price.

114
00:04:33,900 --> 00:04:35,970
So that store ID and price are getting passed

115
00:04:35,970 --> 00:04:38,050
to the ItemModel as arguments.

116
00:04:38,050 --> 00:04:40,490
In the last section we didn't quite have this.

117
00:04:40,490 --> 00:04:42,990
We were only passing in the price,

118
00:04:42,990 --> 00:04:44,920
so this just makes everything a little bit nicer,

119
00:04:44,920 --> 00:04:46,480
and we're doing the same thing down here

120
00:04:46,480 --> 00:04:48,833
as well like there.

121
00:04:50,250 --> 00:04:53,640
The same thing applies to the store.

122
00:04:53,640 --> 00:04:54,473
Sorry, not the store.

123
00:04:54,473 --> 00:04:57,880
The store only has one name,

124
00:04:57,880 --> 00:04:59,790
but the same thing can be applied here

125
00:04:59,790 --> 00:05:00,623
in the UserModel.

126
00:05:00,623 --> 00:05:02,830
As you can see we are passing data username

127
00:05:02,830 --> 00:05:03,970
and data password.

128
00:05:03,970 --> 00:05:07,770
Instead we can just do data like that.

129
00:05:07,770 --> 00:05:09,320
That means exactly the same thing,

130
00:05:09,320 --> 00:05:13,570
just passes username as a named argument

131
00:05:13,570 --> 00:05:15,740
and password as another named argument

132
00:05:15,740 --> 00:05:18,360
into the UserModel, and the values are the ones

133
00:05:18,360 --> 00:05:19,193
that are coming from the parser.

134
00:05:19,193 --> 00:05:21,230
So it just makes things a little bit nicer,

135
00:05:21,230 --> 00:05:23,080
and that's why we're using that here.

136
00:05:24,010 --> 00:05:27,030
Now, in the item resource

137
00:05:28,120 --> 00:05:32,983
we've got this list and map of the json.

138
00:05:34,700 --> 00:05:38,200
What we want to do instead is return a list comprehension

139
00:05:38,200 --> 00:05:40,880
just because list comprehensions are generally

140
00:05:40,880 --> 00:05:43,240
a little bit faster, a little bit more readable

141
00:05:43,240 --> 00:05:44,720
for Python developers.

142
00:05:44,720 --> 00:05:48,220
So I know that we used list and map

143
00:05:48,220 --> 00:05:50,170
over the last few section,

144
00:05:50,170 --> 00:05:51,820
but not we're going to turn over

145
00:05:51,820 --> 00:05:53,640
to list comprehensions just because

146
00:05:53,640 --> 00:05:55,400
they're a bit more Pythonic.

147
00:05:55,400 --> 00:05:56,500
So, all we have to do

148
00:05:56,500 --> 00:05:57,910
to make this into a list comprehension

149
00:05:57,910 --> 00:06:01,920
is say X for X in.

150
00:06:01,920 --> 00:06:02,753
Sorry, x.json

151
00:06:05,520 --> 00:06:08,633
for X in ItemModel query all,

152
00:06:11,212 --> 00:06:12,680
and that's it.

153
00:06:12,680 --> 00:06:14,320
Let's take that away.

154
00:06:14,320 --> 00:06:15,980
So now we're returning the json

155
00:06:17,160 --> 00:06:20,953
of X for X in all the ItemModels

156
00:06:20,953 --> 00:06:21,830
that we query,

157
00:06:21,830 --> 00:06:23,490
and if we want we can of course rename this

158
00:06:23,490 --> 00:06:24,690
to something like item

159
00:06:24,690 --> 00:06:28,010
or whatever else you want to name your variable,

160
00:06:28,010 --> 00:06:29,910
but this is just there for simplicity.

161
00:06:30,950 --> 00:06:32,040
In the store we're gonna do the same thing.

162
00:06:32,040 --> 00:06:35,467
We're gonna go down here and do x.json

163
00:06:38,614 --> 00:06:40,160
for X in that.

164
00:06:42,980 --> 00:06:45,560
Again, just makes it a little bit more readable I feel,

165
00:06:45,560 --> 00:06:47,153
and it's a bit more Pythonic.

166
00:06:49,330 --> 00:06:54,330
Okay, in these store list and item lists

167
00:06:54,570 --> 00:06:57,090
we're also going to modify this slightly.

168
00:06:57,090 --> 00:06:59,850
So instead of accessing the query object

169
00:06:59,850 --> 00:07:04,850
of the store, we are going to do StoreModel.find_all.

170
00:07:05,300 --> 00:07:07,140
Now there's a reason for this,

171
00:07:07,140 --> 00:07:09,600
which is I'm not a big fan

172
00:07:09,600 --> 00:07:11,720
of accessing the query object

173
00:07:11,720 --> 00:07:13,920
from within the resource.

174
00:07:13,920 --> 00:07:15,110
I get the feeling that

175
00:07:15,110 --> 00:07:19,470
it's a bit nicer if we can have a method

176
00:07:19,470 --> 00:07:23,880
that encapsulates accessing the query of a model,

177
00:07:23,880 --> 00:07:27,710
and we don't make the resource access that itself.

178
00:07:27,710 --> 00:07:32,120
The reason for that is, if you access the query object

179
00:07:32,120 --> 00:07:34,770
in the resource, you could essentially

180
00:07:34,770 --> 00:07:39,770
just in many occasions not use the model at all.

181
00:07:40,140 --> 00:07:42,730
You could just access query here,

182
00:07:42,730 --> 00:07:45,550
and, for example, here instead of find by name

183
00:07:45,550 --> 00:07:47,430
you could just use the query object,

184
00:07:47,430 --> 00:07:48,770
and you can do that.

185
00:07:48,770 --> 00:07:50,100
That's totally find,

186
00:07:50,100 --> 00:07:52,350
but it starts making the resource

187
00:07:52,350 --> 00:07:53,570
a bit too heavy.

188
00:07:53,570 --> 00:07:56,280
It starts making the resource interact

189
00:07:56,280 --> 00:07:58,220
with the database if you wish

190
00:07:58,220 --> 00:07:59,543
by doing the querying,

191
00:08:00,390 --> 00:08:02,630
and I think that can get a little bit complicated,

192
00:08:02,630 --> 00:08:04,210
and it was fine down here

193
00:08:04,210 --> 00:08:08,180
to some extent because it was only StoreModel.query.all,

194
00:08:08,180 --> 00:08:10,920
but moving forward we wanna make this a little bit better.

195
00:08:10,920 --> 00:08:14,450
So we are going to create this find_all function,

196
00:08:14,450 --> 00:08:16,649
sorry, method in the StoreModel,

197
00:08:16,649 --> 00:08:20,120
and we are going to use that instead.

198
00:08:20,120 --> 00:08:22,783
So instead of here, we're gonna do classmethod,

199
00:08:23,789 --> 00:08:26,890
find_all, and this is just going to return

200
00:08:26,890 --> 00:08:28,483
cls.query.all,

201
00:08:30,270 --> 00:08:31,860
and that's it,

202
00:08:31,860 --> 00:08:33,320
and of course we don't need a semi colon there.

203
00:08:33,320 --> 00:08:36,050
Sorry, I've been doing a lot of JavaScript recently.

204
00:08:36,050 --> 00:08:38,660
So that's not so good.

205
00:08:38,660 --> 00:08:40,320
Then we have a find_all for the store.

206
00:08:40,320 --> 00:08:43,320
We're gonna add it into the item as well,

207
00:08:43,320 --> 00:08:44,400
and we're going to do the same thing

208
00:08:44,400 --> 00:08:45,390
in the item resource.

209
00:08:45,390 --> 00:08:47,700
So now we've added a find_all method

210
00:08:47,700 --> 00:08:48,650
in the ItemModel.

211
00:08:48,650 --> 00:08:50,410
We're gonna go to the item resource,

212
00:08:50,410 --> 00:08:53,493
and instead of query.all we're gonna do find_all.

213
00:08:54,870 --> 00:08:55,703
That's it.

214
00:08:55,703 --> 00:08:57,200
Remember to save the files by the way.

215
00:08:57,200 --> 00:08:59,753
I tend to forget sometimes,

216
00:09:01,930 --> 00:09:04,810
and that's pretty close to it.

217
00:09:04,810 --> 00:09:06,970
We just wanna add one more thing here

218
00:09:06,970 --> 00:09:10,630
in the json method of the item and the store.

219
00:09:10,630 --> 00:09:13,363
We are going to add just a store_id here,

220
00:09:16,125 --> 00:09:18,043
and it's going to be self.store_id,

221
00:09:20,920 --> 00:09:22,800
and we're also going to add the id

222
00:09:22,800 --> 00:09:26,670
of the item just so we get a bit more information.

223
00:09:26,670 --> 00:09:29,720
Okay, now because this is getting a bit long,

224
00:09:29,720 --> 00:09:32,970
and we don't need that.

225
00:09:32,970 --> 00:09:34,150
Because this is getting a little bit long,

226
00:09:34,150 --> 00:09:35,840
we're just gonna break it down into lines

227
00:09:35,840 --> 00:09:39,973
to make it a bit nicer like that,

228
00:09:41,100 --> 00:09:44,083
and of course we do need the quotation marks there.

229
00:09:44,930 --> 00:09:46,710
Okay, just added two more properties,

230
00:09:46,710 --> 00:09:48,750
id and store_id into the item

231
00:09:48,750 --> 00:09:51,250
so that when we get it with our API,

232
00:09:51,250 --> 00:09:54,910
it's a bit easier to understand what's going on.

233
00:09:54,910 --> 00:09:57,140
In the store model we're gonna do the same,

234
00:09:57,140 --> 00:10:00,700
gonna break it down into lines here,

235
00:10:00,700 --> 00:10:03,570
and we are going to add the id

236
00:10:07,240 --> 00:10:08,260
just like that.

237
00:10:08,260 --> 00:10:12,390
Now the store is returning the id, name, and items

238
00:10:12,390 --> 00:10:14,870
so that we get the id of the store

239
00:10:14,870 --> 00:10:17,503
when we retrieve it using our API.

240
00:10:19,250 --> 00:10:21,150
Now the last thing that you may see

241
00:10:21,150 --> 00:10:24,290
in this project that we've not look at before

242
00:10:24,290 --> 00:10:26,833
is this requirements.txt file.

243
00:10:27,770 --> 00:10:30,750
The requirements.txt file just contains

244
00:10:30,750 --> 00:10:32,470
the three dependencies of our project,

245
00:10:32,470 --> 00:10:36,820
Flask-JWT, FlaskRESTful, and Flask_SQLAlchemy.

246
00:10:36,820 --> 00:10:40,010
We're putting them here so that we can easily remember

247
00:10:40,010 --> 00:10:42,690
and instal them into our virtual environments

248
00:10:42,690 --> 00:10:45,110
when we share this code with someone else

249
00:10:45,110 --> 00:10:47,640
or when we go to a different computer

250
00:10:47,640 --> 00:10:49,180
and want to run this code,

251
00:10:49,180 --> 00:10:51,773
we'll very quickly know what we have to instal.

252
00:10:52,810 --> 00:10:53,890
So that is here.

253
00:10:53,890 --> 00:10:56,280
Requirements.txt is a very common name

254
00:10:56,280 --> 00:10:57,113
for this file.

255
00:10:57,113 --> 00:10:58,640
So make sure to call it that

256
00:10:58,640 --> 00:11:00,933
as that's the convention in Python code.

257
00:11:02,370 --> 00:11:03,203
So that's it for this video.

258
00:11:03,203 --> 00:11:06,100
I'm sorry it's been a little bit of a longer one,

259
00:11:06,100 --> 00:11:09,640
but I just wanted to quickly cover a few changes

260
00:11:09,640 --> 00:11:11,880
from the very last section of the course

261
00:11:11,880 --> 00:11:14,770
into this section because a couple of things

262
00:11:14,770 --> 00:11:16,760
have changed just to make things a bit nice,

263
00:11:16,760 --> 00:11:18,210
and now we are going to move

264
00:11:18,210 --> 00:11:22,870
into implementing Flask-JWT-Extended.

265
00:11:22,870 --> 00:11:25,370
So with that said, I'll see you on the next video.

