AWS Construct error : Type 'Construct' is missing the following properties from type 'Construct': onValidate, onPrepare, onSynthesize

huangapple go评论60阅读模式
英文:

AWS Construct error : Type 'Construct' is missing the following properties from type 'Construct': onValidate, onPrepare, onSynthesize

问题

以下是代码的翻译部分:

在使用AWS + ExpressJs构建后端时,我使用了单个lambda设置。在AuthorizerWrapper中,这是我创建的一个辅助类,用于初始化用户池,我必须在以下方法中使用来自类构造函数的作用域:

import { Construct } from 'constructs';
import * as cdk from 'aws-cdk-lib';
import { CfnOutput } from 'aws-cdk-lib';
import {
  UserPool,
  UserPoolClient,
  CfnUserPoolGroup,
  UserPoolEmail,
} from 'aws-cdk-lib/aws-cognito';
import { IdentityPoolWrapper } from './IdentityPoolWrapper';
import { HttpApi, HttpAuthorizer } from '@aws-cdk/aws-apigatewayv2';

export class AuthorizerWrapper {
  private scope: Construct;
  private api: HttpApi;

  private userPool: UserPool;
  private userPoolClient: UserPoolClient;

  public authorizer: HttpAuthorizer;
  private identityPoolWrapper: IdentityPoolWrapper;

  constructor(scope: Construct, api: HttpApi) {
    this.scope = scope;
    this.api = api;
    this.initalize();
    this.addUserPoolClient();
    this.createAuthorizer();
    this.initializeIdentityPoolWrapper();
    this.createAdminsGroup();
  }

  private initalize() {
    this.userPool = new UserPool(this.scope, 'JobifyUserPool', {
      userPoolName: 'JobifyUserPool',
      selfSignUpEnabled: true,
      signInAliases: {
        email: true,
        username: true,
      },
      passwordPolicy: {
        minLength: 6,
        requireLowercase: false,
        requireDigits: false,
        requireSymbols: false,
        requireUppercase: false,
      },
      userVerification: {
        emailSubject: 'Verify your email for Jobify',
        emailBody: 'Thanks for signing up to Jobify! Your verification code is {####}',
      },
      email: UserPoolEmail.withCognito('test@fane.com'),
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    });

    new CfnOutput(this.scope, 'UserPoolId', {
      value: this.userPool.userPoolId,
    });
  }

  private addUserPoolClient() {
    this.userPoolClient = this.userPool.addClient('JobifyUserPool-client', {
      userPoolClientName: 'JobifyUserPool-client',
      authFlows: {
        userPassword: true,
        adminUserPassword: true,
        custom: true,
        userSrp: true,
      },
      generateSecret: false,
    });

    new CfnOutput(this.scope, 'UserPoolClientId', {
      value: this.userPoolClient.userPoolClientId,
    });
  }

  private createAuthorizer() {
    this.authorizer = new HttpAuthorizer(this, 'JobifyUserAuthorizer', {
      identitySource: ['$request.header.Authorization'],
      jwtAudience: [this.userPoolClient.userPoolClientId],
      jwtIssuer: this.userPool.userPoolProviderUrl,
    });
  }

  private initializeIdentityPoolWrapper() {
    this.identityPoolWrapper = new IdentityPoolWrapper(
      this.scope,
      this.userPool,
      this.userPoolClient
    );
  }

  private createAdminsGroup() {
    new CfnUserPoolGroup(this.scope, 'AdminsGroup', {
      groupName: 'Admins',
      userPoolId: this.userPool.userPoolId,
      roleArn: this.identityPoolWrapper.adminRole.roleArn,
    });
  }
}

请注意,代码中的注释和报错信息未被翻译。如果您需要进一步的帮助,请随时提问。

英文:

So I am building a backend with AWS + ExpressJs using a single lambda setup. In the AuthorizerWrapper, a helper class I created to help me with initializing user pools, I have to use the scope coming from the class constructor in a method as below :

import { Construct } from 'constructs';
import * as cdk from 'aws-cdk-lib';
import { CfnOutput } from 'aws-cdk-lib';
import {
UserPool,
UserPoolClient,
CfnUserPoolGroup,
UserPoolEmail,
} from 'aws-cdk-lib/aws-cognito';
import { IdentityPoolWrapper } from './IdentityPoolWrapper';
import { HttpApi, HttpAuthorizer } from '@aws-cdk/aws-apigatewayv2';
export class AuthorizerWrapper {
private scope: Construct;
private api: HttpApi;
private userPool: UserPool;
private userPoolClient: UserPoolClient;
public authorizer: HttpAuthorizer;
private identityPoolWrapper: IdentityPoolWrapper;
constructor(scope: Construct, api: HttpApi) {
this.scope = scope;
this.api = api;
this.initalize();
this.addUserPoolClient();
this.createAuthorizer();
this.initializeIdentityPoolWrapper();
this.createAdminsGroup();
}
private initalize() {
this.userPool = new UserPool(this.scope, 'JobifyUserPool', {
userPoolName: 'JobifyUserPool',
selfSignUpEnabled: true,
signInAliases: {
email: true,
username: true,
},
passwordPolicy: {
minLength: 6,
requireLowercase: false,
requireDigits: false,
requireSymbols: false,
requireUppercase: false,
},
userVerification: {
emailSubject: 'Verify your email for Jobify',
emailBody:
'Thanks for signing up to Jobify! Your verification code is {####}',
},
email: UserPoolEmail.withCognito('test@fane.com'),
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
new CfnOutput(this.scope, 'UserPoolId', {
value: this.userPool.userPoolId,
});
}
private addUserPoolClient() {
this.userPoolClient = this.userPool.addClient('JobifyUserPool-client', {
userPoolClientName: 'JobifyUserPool-client',
authFlows: {
userPassword: true,
adminUserPassword: true,
custom: true,
userSrp: true,
},
generateSecret: false,
});
new CfnOutput(this.scope, 'UserPoolClientId', {
value: this.userPoolClient.userPoolClientId,
});
}
**  private createAuthorizer() {
this.authorizer = new HttpAuthorizer(this, 'JobifyUserAuthorizer', {
identitySource: ['$request.header.Authorization'],
jwtAudience: [this.userPoolClient.userPoolClientId],
jwtIssuer: this.userPool.userPoolProviderUrl,
});
}**
private initializeIdentityPoolWrapper() {
this.identityPoolWrapper = new IdentityPoolWrapper(
this.scope,
this.userPool,
this.userPoolClient
);
}
private createAdminsGroup() {
new CfnUserPoolGroup(this.scope, 'AdminsGroup', {
groupName: 'Admins',
userPoolId: this.userPool.userPoolId,
roleArn: this.identityPoolWrapper.adminRole.roleArn,
});
}
}

When trying to instantiate a new HttpAuthorizer with this as a Construct I get the error:
Argument of type 'this' is not assignable to parameter of type 'Construct'.
Type 'AuthorizerWrapper' is missing the following properties from type 'Construct': onValidate, onPrepare, onSynthesize

If I try to use this.scope I get:

Argument of type 'import("PATH_TO_PROJECT/cdk/node_modules/constructs/lib/construct").Construct' is not assignable to parameter of type 'import("PATH_TO_PROJECT/cdk/node_modules/@aws/cdk/core/node_modules/constructs/lib/construct").Construct'.

This is my package.json:

{
"name": "cdk",
"version": "0.1.0",
"bin": {
"cdk": "bin/cdk.js"
},
"scripts": {
"build": "tsc",
"watch": "tsc -w",
"test": "jest",
"cdk": "cdk"
},
"devDependencies": {
"@types/aws-serverless-express": "^3.3.5",
"@types/cors": "^2.8.13",
"@types/express": "^4.17.17",
"@types/jest": "^29.4.0",
"aws-cdk-lib": "^2.73.0",
"http-status-codes": "^2.2.0",
"jest": "^29.5.0",
"ts-jest": "^29.0.5",
"typescript": "~4.9.5"
},
"dependencies": {
"@aws-cdk/aws-apigatewayv2": "^1.198.1",
"@aws-cdk/aws-apigatewayv2-integrations": "^1.198.1",
"@aws-cdk/aws-lambda": "^1.198.1",
"aws-sdk": "^2.1343.0",
"aws-serverless-express": "^3.4.0",
"constructs": "^10.1.307",
"cors": "^2.8.5",
"express": "^4.18.2",
"source-map-support": "^0.5.21"
}
}```
</details>
# 答案1
**得分**: 0
以下是翻译好的部分:
"The [idiomatic](https://docs.aws.amazon.com/cdk/v2/guide/best-practices.html#best-practices-constructs) CDK approach would be to make `AuthorizerWrapper` a Construct subclass. See [Writing your own constructs](https://docs.aws.amazon.com/cdk/v2/guide/constructs.html#constructs_author) in the docs. Also idiomatic is a constructor that accepts three arguments like the CDK-defined constructs do: scope, id, and props."
在CDK中,惯用的做法是将 `AuthorizerWrapper` 定义为 Construct 子类。请参考文档中的[编写自定义 constructs](https://docs.aws.amazon.com/cdk/v2/guide/constructs.html#constructs_author)部分。另一个惯用做法是构造函数接受三个参数,就像CDK定义的 constructs 一样:scope、id 和 props。
"In your private methods, `this` will refer to an AuthorizerWrapper instance, which is a Construct."
在你的私有方法中,`this` 将引用一个 AuthorizerWrapper 实例,它是一个 Construct。
"N.B. You are getting the error because as written, `this` is a plain JS object class, not a Construct. Your use of `this.scope` everywhere will work, but is not idiomatic CDK. As the 
(https://docs.aws.amazon.com/cdk/v2/guide/constructs.html#constructs_tree) say:" 注意:你出现错误的原因是因为按照你的写法,`this` 是一个普通的 JavaScript 对象类,而不是一个 Construct。你在各处使用 `this.scope` 可以工作,但不符合CDK的惯用方式。正如[文档](https://docs.aws.amazon.com/cdk/v2/guide/constructs.html#constructs_tree)所说: "Technically, it's possible to pass some scope other than `this` when instantiating a construct. The practical difficulty here is that you can't easily ensure that the IDs you choose for your constructs are unique within someone else's scope. The practice also makes your code more difficult to understand, maintain, and reuse." 从技术上讲,实例化构造时可以传递一些不同于 `this` 的范围。但实际上,这会带来一些困难,因为你无法轻松确保你为构造选择的ID在其他范围内是唯一的。这种做法还会使你的代码变得更难理解、维护和重用。 "You must also fix the `HttpApi` import, which is currently referencing the v1 version. In CDK v2, experimental constructs are in [separate alpha packages](https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html):" 你还需要修复 `HttpApi` 的导入,因为它目前引用的是v1版本。在CDK v2中,实验性 constructs 位于[单独的 alpha 包](https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html)中: ```typescript import { HttpApi } from "@aws-cdk/aws-apigatewayv2-alpha";
英文:

The idiomatic CDK approach would be to make AuthorizerWrapper a Construct subclass. See Writing your own constructs in the docs. Also idiomatic is a constructor that accepts three arguments like the CDK-defined constructs do: scope, id and props.

In your private methods, this will refer to an AuthorizerWrapper instance, which is a Construct.

interface AuthorizerWrapperProps {
  api: HttpApi
}

export class AuthorizerWrapper extends Construct {
  private api: HttpApi;

  constructor(scope: Construct, id: string, props: AuthorizerWrapperProps) {
    super(scope, id);

    this.api = props.api;
    this.initalize();
    // ...
  }

  private initalize() {
    this.userPool = new UserPool(this, &#39;JobifyUserPool&#39;, {
        // ...
    });
}

N.B. You are getting the error because as written, this is a plain JS object class, not a Construct. Your use of this.scope everywhere will work, but is not idiomatic CDK. As the docs say:

> Technically, it's possible to pass some scope other than this when instantiating a construct. The practical difficulty here is that you can't easily ensure that the IDs you choose for your constructs are unique within someone else's scope. The practice also makes your code more difficult to understand, maintain, and reuse.

You must also fix the HttpApi import, which is currently referencing the v1 version. In CDK v2, experimental constructs are in separate alpha packages:

import { HttpApi } from &quot;@aws-cdk/aws-apigatewayv2-alpha&quot;;

huangapple
  • 本文由 发表于 2023年4月11日 16:39:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/75983940.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定