{"record":{"id":"1db6c8945586f1c5","repo":"yikart/AiToEarn","slug":"tweetid-rating-accountid","errorCode":null,"errorMessage":"tweetId, rating和accountId是必须的","messagePattern":"tweetId, rating和accountId是必须的","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"project/aitoearn-electron/server/src/modules/plat/twitter/twitter.controller.ts","lineNumber":368,"sourceCode":"    schema: {\n      type: 'object',\n      properties: {\n        accountId: { type: 'string', description: '账号ID' },\n        tweetId: { type: 'string', description: '推文ID' },\n        rating: { type: 'string', description: '点赞 like、取消点赞  unlike' }\n      },\n      required: ['accountId', 'tweetId', 'rating']\n    }\n  })\n  async rateTweet(\n    @GetToken() systemToken: TokenInfo,\n    @Body('tweetId') tweetId: string,\n    @Body('accountId') accountId: string,\n    @Body('rating') rating: string,\n  ) {\n    const userId = systemToken.id;\n    if (!tweetId || !userId || !accountId || ! rating) {\n      throw new BadRequestException('tweetId, rating和accountId是必须的');\n    }\n\n    const accessToken = await this.twitterAuthService.getUserAccessToken(accountId);\n    // 在方法开始处验证\n    if (![\"like\", \"unlike\"].includes(rating)) {\n        throw new BadRequestException('参数错误: rating必须为like或unlike');\n    }\n\n    // 后续处理\n    if (rating === \"like\") {\n        return this.twitterService.likeTweet(accessToken, userId, accountId, tweetId);\n    } else {\n        return this.twitterService.unlikeTweet(accessToken, userId, accountId, tweetId);\n    }\n  }\n\n}\n","sourceCodeStart":350,"sourceCodeEnd":386,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/modules/plat/twitter/twitter.controller.ts#L350-L386","documentation":"Thrown by the rateTweet endpoint when the body lacks 'tweetId', 'rating', or 'accountId' (userId derives from the token). This is the required-params guard; it fires before the separate rating-value check, so any missing/empty field yields this message.","triggerScenarios":"POST to rateTweet with a body missing tweetId, rating, or accountId; empty-string values; or an unauthenticated token yielding no userId.","commonSituations":"Like/unlike button submits before the tweet id is hydrated; optimistic UI toggles rating but forgets accountId; JSON body malformed so @Body() fields are undefined.","solutions":["Send a JSON body with tweetId, accountId, and rating ('like' or 'unlike').","Ensure Content-Type is application/json so the body is parsed.","Disable the like button until tweetId and accountId are known.","Verify the system token resolves to a userId."],"exampleFix":"// before\nawait api.post('/twitter/tweet/rate', { tweetId });\n// after\nawait api.post('/twitter/tweet/rate', { tweetId, accountId, rating: 'like' });","handlingStrategy":"validation","validationCode":"if (!tweetId || !accountId || !rating) throw new Error('tweetId, accountId和rating是必须的');\nawait api.post('/twitter/tweet/rate', { tweetId, accountId, rating });","typeGuard":"function isRateRequest(p: unknown): p is { tweetId: string; accountId: string; rating: string } {\n  const o = p as any;\n  return typeof o?.tweetId === 'string' && o.tweetId.length > 0 &&\n    typeof o?.accountId === 'string' && o.accountId.length > 0 &&\n    typeof o?.rating === 'string' && o.rating.length > 0;\n}","tryCatchPattern":"try {\n  await api.post('/twitter/tweet/rate', { tweetId, accountId, rating });\n} catch (e) {\n  if (e.response?.status === 400) revertOptimisticLikeState();\n}","preventionTips":["Disable like/unlike buttons until tweetId and accountId are populated.","Send JSON with Content-Type: application/json.","Validate params client-side before optimistic UI updates.","Roll back optimistic state when the API returns 400."],"tags":["nestjs","validation","bad-request","missing-parameter","request-body"],"backgroundTag":"missing-required-parameter","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}