DrillLab
练习Practice

动手做Get your hands on it

练习跟着课文走 —— 每节课尾都有本课的练习。这一页是全部练习的总库,想集中刷题的时候来。 每个练习都写清了它来自哪一节,卡住了就回去看那一节。Practice follows the lessons — every lesson ends with the exercises for that lesson. This page is the whole library, for when you want to drill in one sitting. Each exercise names the lesson it came from, so you can go back when you stall.

0 / 148个做对过you got right

练习Exercises

筛出 148 个练习 · 第 8 / 13 页。Showing 148 · page 8 / 13.
来自From entity、@key 与 __resolveReferenceentity, @key and __resolveReference · Federation 考试Federation exam
L1认出来Spot itUser.orders 里的 user 参数上有什么What the user argument of User.orders carries

__resolveReference 返回 { id: user.id }。 那么 User.orders(user, ...) 里的 user上有哪些属性?

__resolveReference returns { id: user.id }. So which properties does user have inside User.orders(user, ...)?

先选一个选项Pick an option first
来自From entity、@key 与 __resolveReferenceentity, @key and __resolveReference · Federation 考试Federation exam
L2填空Fill the blanks补全 entity 声明与引用解析Fill in the entity declaration and the reference resolver

三个空。第一个是 directive,第二个是标记「这不是我的字段」, 第三个是引用解析要返回什么。

Three blanks. The first is a directive, the second marks a field as not belonging to this service, and the third is what the reference resolver returns.

GRAPHQLschema.graphql + orderResolvers.js3 个空3 blanks
1# schema.graphql
2type User (fields: "id") {
3 id: ID!
4 orders: [Order!]!
5}
6
7# orderResolvers.js
8# User: {
9# __resolveReference(user, { dataSources, loaders }) {
10# return { id: };
11# },
12# ...
13# }
把 3 个空都填上才能检查(还差 3 个)Fill all 3 blanks to check (3 to go)
来自From N+1 问题与 DataLoaderThe N+1 problem and DataLoader · Federation 考试Federation exam
L1认出来Spot itDataLoader 靠什么把 N 次合并成 1 次How DataLoader turns N calls into 1

下面哪一条最准确?

Which of these is most accurate?

先选一个选项Pick an option first
来自From N+1 问题与 DataLoaderThe N+1 problem and DataLoader · Federation 考试Federation exam
L1认出来Spot itbatch 函数里哪种写法是错的Which return value from a batch function is wrong

batch 函数收到 ids = ['a', 'b', 'c'], 其中 b 在数据库里不存在。下面哪种返回是错的?

The batch function receives ids = ['a', 'b', 'c'], and b does not exist in the database. Which of these return values is wrong?

先选一个选项Pick an option first
来自From N+1 问题与 DataLoaderThe N+1 problem and DataLoader · Federation 考试Federation exam
L2填空Fill the blanks修好 createOrderLoader 并写出 shippingInfoFix createOrderLoader and write shippingInfo

两个空。第一个要你填对数据源上真实存在的方法名, 第二个要你用 loader 而不是数据源。

Two blanks. The first wants the name of a method that really exists on the data source; the second wants you to go through the loader rather than the data source.

JSsrc/resolvers/orderResolvers.js2 个空2 blanks
1function createOrderLoader(orderDataSource) {
2 return new DataLoader(async orderIds => {
3 const orders = await Promise.all(
4 orderIds.map(id => orderDataSource.(id))
5 );
6 return orders;
7 });
8}
9
10// Order.shippingInfo —— 必须走 loader,否则 N+1 考点没答到
11async shippingInfo(parent, _, { dataSources, loaders, correlationId }) {
12 const shippingInfo = await loaders..load(parent.id);
13 return shippingInfo ?? null;
14}
把 2 个空都填上才能检查(还差 2 个)Fill all 2 blanks to check (2 to go)
来自From N+1 问题与 DataLoaderThe N+1 problem and DataLoader · Federation 考试Federation exam
L2Debug LabDebug LabDebug Lab · DataLoader 报 is not a functionDebug Lab · DataLoader reports is not a function

npm test,其中一个 DataLoader 相关的测试挂了。 报错指向 loader 内部。

You run npm test and one of the DataLoader tests fails. The error points inside the loader.

第 1 步 · 先看现象和代码,别急着改Step 1 · read the symptom and the code before you touch anything
● Order Resolvers › DataLoader functionality › should batch multiple order requests TypeError: orderDataSource.getOrderById is not a function 29 | 30 | const orders = await Promise.all( > 31 | orderIds.map(id => orderDataSource.getOrderById(id)) | ^ 32 | ); 33 | 34 | return orders; at src/resolvers/orderResolvers.js:31:42 at Array.map (<anonymous>) at DataLoader._batchLoadFn (src/resolvers/orderResolvers.js:31:16)
JavaScriptsrc/resolvers/orderResolvers.js示意Illustrative
1function createOrderLoader(orderDataSource) {
2 return new DataLoader(async orderIds => {
3 const orders = await Promise.all(
4 orderIds.map(id => orderDataSource.getOrderById(id))
5 );
6 return orders;
7 });
8}
9
10// 参考:OrderDataSource 上真实存在的方法
11// class OrderDataSource {
12// async getOrder(id) { ... }
13// async getOrdersByUserId(userId) { ... }
14// async createOrder(userId, items) { ... }
15// }
1function createOrderLoader(orderDataSource) {
2 return new DataLoader(async orderIds => {
3 const orders = await Promise.all(
4 orderIds.map(id => orderDataSource.getOrderById(id))
5 );
6 return orders;
7 });
8}
9
10// For reference: the methods OrderDataSource really has
11// class OrderDataSource {
12// async getOrder(id) { ... }
13// async getOrdersByUserId(userId) { ... }
14// async createOrder(userId, items) { ... }
15// }
第 2 步 · 这是什么类型的错误Step 2 · what kind of error is this
来自From 先读题:四个 TODO、三处埋雷、十个测试Read the task first: four TODOs, three planted bugs, ten tests · Federation 考试Federation exam
L1认出来Spot it为什么基线里有 4 个测试是通过的Why 4 tests already pass at the baseline

四个 TODO 全都只写了 return []return null,为什么还有 4 个测试通过?

All four TODOs contain nothing but return [] or return null. So why do 4 tests still pass?

先选一个选项Pick an option first
来自From 先读题:四个 TODO、三处埋雷、十个测试Read the task first: four TODOs, three planted bugs, ten tests · Federation 考试Federation exam
L1认出来Spot it埋雷 1 该在哪个文件修Which file should planted bug 1 be fixed in

createOrderLoader 调了不存在的orderDataSource.getOrderById(id)。 正确的修法是?

createOrderLoader calls orderDataSource.getOrderById(id), which does not exist. What is the right fix?

先选一个选项Pick an option first
来自From 先读题:四个 TODO、三处埋雷、十个测试Read the task first: four TODOs, three planted bugs, ten tests · Federation 考试Federation exam
L1排顺序Order it把 Task 1 的推进顺序排对Put the steps of Task 1 in the right order

拿到 node-subgraph,最合理的动作顺序?

You have just opened node-subgraph. What is the most sensible order to work in?

1逐个实现四个 TODOImplement the four TODOs one by one
2读 schema.graphql,记下四个返回类型的可空性Read schema.graphql and note the nullability of the four return types
3npm install,然后 npm test 拿到 6 failed / 4 passed 的基线npm install, then npm test to get the 6 failed / 4 passed baseline
4npm test 转绿,再写个 verify 脚本查 _service 和 _entitiesOnce npm test is green, write a verify script that checks _service and _entities
5读 index.js 和 dataSources,抄下 context 键名与方法名Read index.js and the dataSources, and copy out the context keys and method names
6修三处埋雷Fix the three planted bugs
来自From TODO 1 · User.ordersTODO 1 · User.orders · Federation 考试Federation exam
L2填空Fill the blanks补全 User.ordersFill in User.orders

四个空。第 2 个是数据源上的真实方法名, 第 4 个是那行最容易漏的防御。

Four blanks. The second is the method name that really exists on the data source; the fourth is the guard people most often forget.

JSsrc/resolvers/orderResolvers.js4 个空4 blanks
1async orders(user, _, { dataSources, loaders, correlationId }) {
2 try {
3 console.log(`[${correlationId}] Resolving User.orders for userId: ${user.}`);
4
5 const orders = await dataSources.orderDataSource.(user.id);
6
7 return orders [];
8 } catch (error) {
9 if (error GraphQLError) throw error;
10
11 console.error(`[${correlationId}] Error:`, error.message);
12 throw new GraphQLError('Failed to fetch orders for user', {
13 extensions: { code: ErrorCodes.SERVICE_ERROR, correlationId }
14 });
15 }
16}
把 4 个空都填上才能检查(还差 4 个)Fill all 4 blanks to check (4 to go)
来自From TODO 1 · User.ordersTODO 1 · User.orders · Federation 考试Federation exam
L3写整块Write a block不看答案,自己写出 User.ordersWrite User.orders yourself, without looking at the answer

按 TODO 的三条要求写完整实现。检查器会核对方法名、兜底、 错误处理和 correlation id。

Write the full implementation against the three requirements in the TODO. The checker looks at the method name, the fallback, the error handling and the correlation id.

要求Requirements
  • 用 user.id 去取该用户的订单Use user.id to fetch that user's orders
  • 调用数据源上真实存在的方法Call a method that really exists on the data source
  • 绝不返回 null 或 undefined(schema 是 [Order!]!)Never return null or undefined (the schema says [Order!]!)
  • 用 try/catch 包住,失败时抛 GraphQLErrorWrap it in try/catch and throw a GraphQLError on failure
  • 错误的 extensions 里带 code 和 correlationIdPut code and correlationId in the error's extensions
  • 已经是 GraphQLError 的错误要原样往上抛,不要重新包装Rethrow an error that is already a GraphQLError untouched, without rewrapping it
  • 日志里带上 correlationIdInclude correlationId in the log line
JavaScriptsrc/resolvers/orderResolvers.js
This check is textual: it looks for the right constructs, it does not run your code
提示Hints共 4 级,已看 0 级4 levels, 0 opened
先自己想两分钟。想不出来再点右上角 —— 提示是一级一级放的,不会一次给完。Think for two minutes first. Then use the button above — hints come one level at a time, never all at once.

看答案之前,先确认你已经自己动手写过一遍。看懂别人的答案和自己写出来,是两种能力。Before you open this, make sure you have written it yourself once. Following someone else's answer and producing your own are two different skills.

来自From TODO 2 · Order.shippingInfoTODO 2 · Order.shippingInfo · Federation 考试Federation exam
L2填空Fill the blanks补全 Order.shippingInfoFill in Order.shippingInfo

三个空。第 1 个决定你答不答得到 N+1 考点, 第 3 个决定第二条测试过不过。

Three blanks. The first decides whether you answer the N+1 question at all; the third decides whether the second test passes.

JSsrc/resolvers/orderResolvers.js3 个空3 blanks
1async shippingInfo(parent, _, { dataSources, loaders, correlationId }) {
2 try {
3 const shippingInfo = await .shippingInfoLoader.load(parent.);
4
5 return shippingInfo ?? ;
6 } catch (error) {
7 if (error instanceof GraphQLError) throw error;
8 console.error(`[${correlationId}] Error:`, error.message);
9 throw new GraphQLError('Failed to fetch shipping info', {
10 extensions: { code: ErrorCodes.SERVICE_ERROR, correlationId, orderId: parent.id }
11 });
12 }
13}
把 3 个空都填上才能检查(还差 3 个)Fill all 3 blanks to check (3 to go)