TypeScript 인터페이스에서 요청 모델을 자동으로 생성하는 방법

17670 단어 typescriptawscdk
나♥️ AWS CDK(big CDK fan boi)와 CDK와 AWS를 사용하고 있는 APIGAteway 프로젝트 몇 개.그러나 모든 내용을 수동으로 정의하지 않으면 API 요청 검증이 쉽지 않습니다...지금까지?

하지만왜 검증을 요구합니까?
요청 검증을 사용하면 실제 호출 뒤에 있는 lambda 이전에 API를 통해 요청한 요청이 유효한지 확인할 수 있습니다.이것은 약간의 원가를 절약할 수 있을 뿐만 아니라, 추가적인 안전 이익도 가져올 수 있을 것이다.
본고는 요청 검증을 집행하는 기초지식과 자동화의 기초지식을 소개한다.이것은 설정 API (이 프로젝트에서 추정할 수 있지만) 나 프로젝트 사용에 관한 강좌가 아닙니다.만약 당신이 이것에 관한 문장을 보고 싶다면...댓글로 알려주세요!
본고의 코드는 다음과 같다. github.com/martzcodes/blog-ts-request-validation.

코드의 일반적인 구조는 무엇입니까?


이 프로젝트는 projen 를 사용하여 작성되었습니다.이것은 내가 처음으로 그것을 사용한 것이지만, 그것은 상당히 편리한 기능을 가지고 있다.나는 미래에 그것을 추적하기를 기대하고 있다.중요 파일은 src/ 폴더에 있습니다.
  • src/main.ts CDK 스택을 정의하는 곳
  • src/lambdas 매우 간단한 lambda를 정의했다...그것들은 기본적으로 요청 경로와 본문 입력이 있는 텍스트 문자열만 출력한다
  • src/interfaces 두 개의 lambda
  • 가 사용하는 인터페이스를 포함한다
  • src/interfaces/basic.ts는 기본 인터페이스...문자열과 숫자 속성만 있습니다.
  • src/interfaces/advanced.ts 옵션 속성이 있고 Basic 인터페이스
  • 를 끌어당기기 때문에 더욱 복잡합니다.
    창고에api와 두 개의 루트 자원이 있습니다...validatedunvalidated...그냥 비교하기 편하게.둘 다 같은 lambda를 가리키는 단점이 있다.

    검증 요청은 어떻게 작동합니까?


    나의 리셋 프로토콜의 simple 지점은 API 게이트웨이의 비자동 버전을 가지고 있다.
    초기 설정 후 일반 리소스를 만듭니다.
    const validatedResource = restApi.root.addResource('validated');
    const validatedHelloResource = validatedResource.addResource('{hello}');
    const validatedHelloBasicResource = validatedHelloResource.addResource(
        'basic',
    );
    
    요청체 검증을 위해 모델을 정의해야 합니다.
  • https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.Model.html
  • https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.JsonSchema.html
  • const basicModel = restApi.addModel('BasicModel', {
        contentType: 'application/json',
        modelName: 'BasicModel',
        schema: {
        schema: JsonSchemaVersion.DRAFT4,
        title: 'basicModel',
        type: JsonSchemaType.OBJECT,
        properties: {
            someString: { type: JsonSchemaType.STRING },
            someNumber: { type: JsonSchemaType.NUMBER, pattern: '[0-9]+' },
        },
        required: ['someString', 'someNumber'],
        },
    });
    
    주의: 사실이 증명하듯이 검증 요청기는 한 숫자가 한 숫자라는 것을 진정으로 검증하지 않았다.해결 방법은 정규 표현식 모델을 사용하여 검증하는 것이다.
    다음우리는 API 자체에 검증기를 정의한다...여기서 우리가 말하는 것은 요청 매개 변수와 요청체 검증이 반드시 유효해야 한다는 것이다.
    const basicValidator = restApi.addRequestValidator('BasicValidator', {
        validateRequestParameters: true,
        validateRequestBody: true,
    });
    
    마지막다음 메서드에 추가합니다.
    validatedHelloBasicResource.addMethod(
        'POST',
        new LambdaIntegration(basicLambda),
        {
        requestModels: {
            'application/json': basicModel,
        },
        requestParameters: {
            'method.request.path.hello': true,
        },
        requestValidator: basicValidator,
        },
    );
    
    validateRequestParameters 정의가 필요합니다...모든 매개변수는 자동으로 검증되지 않습니다.형식이 좀 이상하지만 문서에 정의가 있습니다. https://docs.aws.amazon.com/apigateway/latest/developerguide/request-response-data-mappings.html
    기본적으로, 자원에서 경로 파라미터를 뭐라고 명명하든지, (내 예에서 requestParameters requestParameters 대상에서 hello 으로 정의해야 합니다.method.request.path.<path parameter you care about> 더 재미있어졌다.좋은 문서 기록은 없지만 모델은 인용을 통해 서로 계승할 수 있다.그래서 우리는 고급 인터페이스가 기본 인터페이스에서 도입된 것을 안다...우리는 어떻게 모델에 대해 같은 처리를 진행합니까?
    basic: {
        ref: `https://apigateway.amazonaws.com/restapis/${restApi.restApiId}/models/${basicModel.modelId}`,
    },
    
    이것은 모델이 최종적으로 무슨 일이 일어날지 흔히 볼 수 있는 형식이다.URL이 일반/다른 항목으로 변경되지 않았습니다...모든 것이 apigateway로 정의됩니다.amazonaws.com/restapis...일반적인 실행apiurl 대신

    그러면 간단한 검증은 어떤 모습일까요?


    예시를 신속하게 완성하기 위해서 우리는 6개의 테스트를 진행할 것이다.3개는 검증되지 않은api에, 3개는 검증된api에 있습니다.우리는 이 두 가지 측면에서 두 번의 실패가 발생할 것이라고 예상한다.
    # Unvalidated - Valid
    $ curl --location --request POST 'https://<your api url>/prod/unvalidated/sdfg/basic' \
    --header 'Content-Type: application/json' \
    --data-raw '{
        "someString": "qwerty",
        "someNumber": 1234
    }'
    Hello sdfg.  How many times have you qwerty?  1234 times.%
    
    # Unvalidated - Invalid
    $ curl --location --request POST 'https://<your api url>/prod/unvalidated/sdfg/basic' \
    --header 'Content-Type: application/json' \
    --data-raw '{
        "someString": "qwerty",
        "someNumber": "asdf"
    }'
    Hello sdfg.  How many times have you qwerty?  asdf times.%
    
    # Unvalidated - Missing Path Param
    $ curl --location --request POST 'https://<your api url>/prod/unvalidated//basic' \
    --header 'Content-Type: application/json' \
    --data-raw '{
        "someString": "qwerty",
        "someNumber": 1234
    }'
    Hello no one.  How many times have you qwerty?  1234 times.%  
    
    # Validated - Valid
    $ curl --location --request POST 'https://<your api url>/prod/validated/sdfg/basic' \
    --header 'Content-Type: application/json' \
    --data-raw '{
        "someString": "qwerty",
        "someNumber": 1234
    }'
    Hello sdfg.  How many times have you qwerty?  1234 times.%
    
    # Validated - Invalid
    $ curl --location --request POST 'https://<your api url>/prod/validated/sdfg/basic' \
    --header 'Content-Type: application/json' \
    --data-raw '{
        "someString": "qwerty",
        "someNumber": "asdf"
    }'
    {"message": "Invalid request body"}%
    
    # Validated - Missing Path Param
    $ curl --location --request POST 'https://<your api url>/prod/validated//basic' \ 
    --header 'Content-Type: application/json' \
    --data-raw '{
        "someString": "qwerty",
        "someNumber": 1234
    }'
    {"message": "Missing required request parameters: [hello]"}%
    
    마지막 두 개가 바로 저희가 보고 싶은 거예요!더 좋은 것은...이런 상황에서 람다를 호출하지 않았습니다.

    좋아, 다행이야...하지만 JSON 모드를 실제 코드와 동기화해야 합니다?!?


    예.추상적인 문법 트리(AST)에 창의적이지 않으면
    두 개 (또는 그 이상) 다른 곳에서 같은 기본 내용을 업데이트해야 한다는 것이 나를 화나게 한다.인터페이스를 쉽게 변경할 수 있고 그것과 조립된 모델을 업데이트하는 것을 잊을 수 있다.
    현재 내가 조회할 중요한 파일은 https://github.com/martzcodes/blog-ts-request-validation/blob/main/src/util/ast.ts
    여기에서 TypeScripts API를 사용하여 폴더의 모든 인터페이스를 분석하고 API 게이트웨이 모델이 원하는 JSON 모드 형식으로 출력합니다.AST 사용하기 좀 귀찮아...이것은 결코 가장 직관적인 API가 아니기 때문에 많은 시도와 오류가 있다.만약 당신이 이 점을 어떻게 개선하는지에 대해 어떤 건의가 있다면, 저에게 알려주세요.
    코드에 주석을 추가했습니다...하지만 고위층:
  • 폴더의 파일 목록 가져오기
  • 인터페이스를 확보하고 차원 구조를 확인하기 위해 검사
  • 먼저 하위 노드를 모델로 생성하고 이전에 정의된 노드를 참조하기 위해 하위 노드부터 처리합니다.
  • 실제 모드를 생성하고 창고에서 정의합니다.
  • 이제 스택의 실제 API에 모델을 추가할 수 있습니다.
    const models: { [key: string]: Model } = {};
    Object.keys(modelSchemas).forEach((modelSchema) => {
        if (modelSchemas[modelSchema].modelName) {
        models[modelSchema] = restApi.addModel(
            modelSchemas[modelSchema].modelName || '',
            modelSchemas[modelSchema],
        );
        }
    });
    
    실제 방법에서는 생성된 모델을 사용하려면 모델을 업데이트해야 합니다.
    // Basic is the interface in this case
    requestModels: {
        'application/json': models.Basic,
    },
    
    같은 테스트를 실행하면 같은 결과가 나오지만 인터페이스는 한 곳에서만 정의됩니다.창고를 배치할 때마다 typescript 인터페이스에서 모델을 다시 생성합니다.

    다음 단계?


    이와 관련된 수동 프로세스도 있습니다. 약속을 조심스럽게 명명해야 합니다.당신은 이것에 대해 어떤 개선을 할 것입니까?

    좋은 웹페이지 즐겨찾기