跟讀練習: Your API Can’t Handle Real-World Integrations - 通過影片學習英語口語
選擇練習模式
每種模式都會開啟全屏練習室。
180 句
如果句子過短或過長,請點選 Edit 進行調整。
1
Let's say you build a nice REST API product, but then you release it and you find out your customers can't integrate it with their own systems.
2
One customer needs a CRM ID, another needs a warehouse reference,
3
and someone asks whether you can just add one more field for some external system that they use.
4
And before you know it, your schema becomes a huge mess.
5
Now, in this video I'll show you a much cleaner approach that won't require you turning your API into a junk drawer.
6
It's very simple to build, the Stripe API does it this way, and I think more APIs should add this feature because it makes them way more usable.
7
Now, what I've learned over the years is that with ideas like this, it's not just important that you know they exist, but that you also understand the design trade-offs behind them.
8
And that's exactly what I go deep into in Software Design Mastery.
9
This is not just another course with patterns and principles, it's a comprehensive system for thinking about design and trade-offs.
10
If you want to be part of that, join the waiting list at iron.codes.mastery.
11
The link is in the description.
12
Now, I'm starting with a simple working FastAPI app.
13
So this is the main file.
14
I'm using a SQL Alchemy database for this FastAPI app.
15
And it's very basic.
16
It just has a few concepts.
17
So there is a customer, there is a product, and there are orders.
18
And this is what the API allows us to work with.
19
And as you can see, I have a declarative base, just like you're supposed to do with SQLAlchemy.
20
And then I create these different classes.
21
So customer has ID, email, name, there are orders, there are products, there are also mapped to orders.
22
And an order itself is, again, linked to a customer and a product and has some other data as well.
23
This is a pretty basic setup.
24
And by the way, the full code example, as usual, you can find in the code example, Git repository.
25
The link is also in the description of the video.
26
Now next to these models there is a couple of other modules as well, like the routes, which is the most important one,
27
where we have different endpoints like posting to the customer's endpoint to create a new customer.
28
There is an endpoint for getting the customer by ID.
29
You can patch a customer.
30
You can do the same thing for products and the same thing for orders as well.
31
So let's start this API using UVcorn.
32
And now I can send a simple request to create a new customer.
33
Like so.
34
Now we have this customer with ID 1.0.
35
And then I can use the API in different ways.
36
For example, here I'm retrieving that same customer from the database that I just created.
37
Now, once this app starts integrating with other systems, then new requirements are going to appear very quickly.
38
Maybe one of your clients has a CRM
39
and they want their own customer ID that they store along with the customers in your API.
40
Or some accounting system wants a contact reference.
41
or a warehouse tool wants an order reference, a migration script wants to remember some old legacy identifier.
42
And these fields are really important, but they're not really part of the core domain model of your API.
43
You can't know in advance what all these fields are going to be
44
because they're going to be dependent on the clients that use your API.
45
These are really integration specific.
46
Now, some APIs offer custom fields for this
47
and then it's often implemented like you need to specify what custom fields there are.
48
These things get their own ID and then you can read
49
or write these custom fields that are then attached to different resources in your API.
50
But there is actually a simpler way to do it and that's by using a really great data structure called JSON.
51
The idea is, and this is also how Stripe sort of does it is
52
that you have a metadata or custom data field
53
that is a JSON format that your customer can basically set in any way that they want.
54
But you don't just want to add a JSON field
55
and leave it at that because then it's not really usable
56
because if you want to update let's say one value in
57
that JSON structure you need to pass in the complete JSON
58
data into the request in order not to delete everything that's in there.
59
So we need to implement it in a specific way
60
and that's also how it's done in stripe
61
and you can actually add this to your api as well
62
so we want let's call it custom data to behave like
63
a normal field in the api clients should be able to
64
send it on create request they should be able to update it
65
and pass request and it should also be able to remove individual keys without replacing the whole object
66
so they should be able to send a key value pair to add
67
or update the value they should be able to send a key with a null value
68
which will unset it
69
and they should also be able to send an empty object to basically clear all of the custom data
70
and combine this gives you a very flexible and predictable behavior
71
that works very well for apis
72
so how do we add this here well there's a very logical place in the database models actually
73
which is that we have this declarative base
74
because obviously we want this custom data to be available for all of the different resources for customers for products
75
and for orders and we want to avoid
76
that we copy this all over the place
77
so what you can do here is actually rely on inheritance
78
even though i'm personally more of a fan of composition in this case i think inheritance is a good solution
79
because it's already built into sql alchemy
80
so what we'll do is we will add this custom data field to the declarative base
81
so when you do that this is actually what that looks like
82
so base now has a custom data field it's a json type we won't allow it to be null
83
because we always want it to be an object
84
so that's what we have
85
but now the only thing we need to do is of
86
course define the behavior of changing this custom data object now you could add
87
that to the routes but again you'd have to copy paste
88
that behavior all over the place and actually there is a very easy way to add it to declarative base in SQLAlchemy.
89
The first thing that you can do is define a function that applies the data to the custom data.
90
So and then we'll call this from somewhere else.
91
So this gets a dictionary with the new data and there we basically have to work with the three different cases.
92
The first case is very simple that if the patch is the empty dictionary then
93
self.customData is simply going to be the empty dictionary and we're done.
94
We can return.
95
So this is basically a way of clearing the custom data.
96
The next step is that we can go through the key value pairs in the patch and apply them one by one.
97
So first let's store the custom data in a temporary variable.
98
And if that doesn't happen to exist, let's make it the empty object.
99
So we don't run into any issues we always note that there is an object.
100
So for key, the value in the items of patch,
101
and then now we can handle the two remaining values.
102
So if the value is none, that means that we want to unset the key.
103
So we do current.pop the key.
104
And default, if the key doesn't exist, we simply ignore it.
105
Else, that means the key has a value.
106
So in that case, current key equals the value.
107
So we simply set the value.
108
And then finally, once we've done this, we set the custom data to the current object,
109
so that this is also handled correctly if this is the empty dictionary.
110
Now maybe you could do this directly on the custom data, but I kind of like using a temporary variable here feels a bit safer.
111
But now the magic is that we can have a method apply patch and this gets data.
112
And this actually overrides a standard method in the declarative base.
113
So this is going to be called automatically whenever we update the object.
114
And here what we're going to do is we're going to loop over the items in data
115
and then we can simply handle the cases here.
116
So if the value is none and the key is not custom data we can simply ignore this case.
117
And if the key is custom data,
118
well in that case we're going to call our custom data patch method
119
and we're simply going to pass the data like
120
so else we can use setAther to set the key to the value
121
so this basically means the standard behavior of SQLAlchemy
122
and then the only thing left to do is
123
that in our schemas for creating and reading customers and
124
so on we have to make sure that there is a custom data field.
125
So here's how you could do that.
126
It's very simple.
127
We simply define custom data as part of our schema by simply adding it there to the classes.
128
So in this case I created a custom data schema
129
and then whenever I create a customer I make a subclass of
130
that so we can also set the custom data whenever we create the customer.
131
And I did the same thing for reading the customers
132
and you can also add it for other things like creating products for example.
133
So adding the custom data here is actually very little work.
134
So now that we have this, it's really easy to add custom data to our resources.
135
For example, here I'm creating a new customer where I set an actual customer ID in the CRM
136
that I pass as custom data and now my customer has this as part of the object. And
137
if I want to add more custom data I can actually
138
simply pass it by setting a key value pair in the custom data like so.
139
And as you can see it currently does something weird
140
which is that it puts custom data inside the custom data and that's because I made a mistake.
141
Namely when I apply the catch I shouldn't pass all the data here I should actually pass the value like so.
142
Let's try this again I've deleted the database
143
and I'm creating the customer one more time and now let's add another custom data field.
144
As you can see now it has the desired behavior
145
so now it sets our billing ID but it doesn't delete the CRM custom ID which is really neat.
146
We can also remove a custom field value by simply setting the value to null like so.
147
As you can see We get the customer back.
148
It keeps the CRM customer ID, but it has deleted billing ID.
149
And finally, if we want to clear all custom data, we simply set it to the empty object.
150
And that also works.
151
So overall, I think this is a really useful pattern you can add to your API.
152
And it's actually really simple to do, especially if you're using something like SQL Alchemy.
153
The only thing you need to do is basically add this piece of code to your declarative base.
154
And anything that inherits from this is going to have custom data with the behavior that I demonstrated in this video.
155
And of course, you need to make sure that custom data is part of your schemas, but that's like a pretty easy thing to add.
156
So in my opinion, more APIs should add this feature because this is really useful, but only use this for the right thing.
157
So good uses for this are external IDs that you want to couple with,
158
integration-specific references, small optional flags or tags, data that is useful context but not core domain structure.
159
I wouldn't use this to store important business logic or data
160
that you constantly need to query or search through things that really should be first-class fields in your API.
161
Now a good rule of thumb is that
162
if the field is part of the meaning of the model make it a real column.
163
If it's just custom context then it fits great into a custom data object like this.
164
And by the way
165
if you enjoy these types of practical design breakdowns where we go beyond just making something work
166
and look at why design is good
167
or bad like this video subscribe to the channel it helps
168
me out a lot in summary what makes this feature nice is
169
that it's not just storing JSON but that we slightly modify the behaviors
170
that it's really easy to use
171
and by making it part of the declarative base it's really
172
easy to add to the various resources in your API
173
but I'd like to see what you think have you added
174
this type of metadata custom data thing to your API's have
175
you seen other API's implement this feature let me know in
176
the comments I haven't talked much about how to actually organize
177
the business logic in this API like the database the routes
178
anything else your API needs watch this video next to learn more about how to properly design
179
and using a really cool pattern called ports and adapters.
180
Thanks for watching and see you next time.
同頻道
FOR YOU
推薦影片
為什麼要通過這個影片練習口語?
通過觀看和模仿這個影片,你可以有效地提高你的英語口語練習能力。影片中展示瞭如何構建一個REST API,這為學習者提供了一個專業且真實的語境,幫助你理解技術英文的表達方式。藉助這樣的內容進行英語影子跟讀,可以提高你的發音和語調,使你在技術溝通中更加流利自信。此外,通過專業術語和對話的練習,你能夠增強在雅思口語練習中的表現,提升整體語言能力。
語法與表達解析
在影片中,以下是一些關鍵的句型和結構:
- “Let's say you build...” - 這個句型用來引入假設情況,非常適合討論理論或示例。
- “Now, I’m starting with...” - 表達出正在進行的動作,適用於自我介紹或概述內容的場合。
- “So you can find…” - 用來引導聽眾注意到某個資訊,適合在解釋步驟或指引時使用。
- “By the way, the full code example...” - 提供附加資訊的表達方式,非常適合用在分享資料或額外內容時。
這些句型在shadowspeak中運用得當,可以幫助學習者更流利地表達自己的想法。
常見發音陷阱
在影片中,有一些詞彙和短語的發音可能會讓學習者感到困惑:
- “API” - 確保清楚地發音每個字母,避免說成“艾比”而應為“艾皮”。
- “integration” - 注意這個詞的重音在第二節,常見錯誤包括將重音放在第一個音節。
- “schema” - 要確保發音為“斯基馬”,常有學習者錯誤發音為“西瑪”。
通過反覆的練習和shadowspeak,你能夠克服這些發音障礙,大大提升你的口語能力。利用這樣的內容進行雅思口語練習,將極大提升你的自信和流利程度。
影片中的語法
說話人最常用的結構,並附上影片中的原話:
| 結構 | 影片中的用法 |
|---|---|
| 現在完成時 have/has + 過去分詞 — 過去發生但與現在仍有關聯的事 | I've learned · we've done · I've deleted |
| 被動語態 be + 過去分詞 — 強調發生了什麼,而不是誰做的 | are then attached · is also handled · be called |
什麼是跟讀法?
跟讀法 (Shadowing) 是一種有科學依據的語言學習技巧,最初開發用於專業口譯員的培訓,並由多語言者Alexander Arguelles博士普及。這個方法簡單而強大:您在聽英語母語原聲的同時立即大聲重複——就像是一個延遲1-2秒緊跟說話者的影子。與被動聽力或語法練習不同,跟讀法強迫您的大腦和口腔肌肉同時處理並模模擬實的講話模式。研究表明它能顯著提高發音準確性,語調,節奏,連讀,聽力理解和口語流利度——使其成為雅思口語備考和真實英語交流最有效的方法之一。













