amazon-web-servicesaws-cdkaws-cdk-typescript

How do I add missing 'IChainable' properties to my own construct so that I can use it within a state machine definition?


I have written my own construct that instantiates a new Pass step for a state machine:

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as sfn from 'aws-cdk-lib/aws-stepfunctions';

export interface GlueAuthorizationProps {}

export class GlueAuthorization extends Construct {
  
  constructor(scope: Construct, id: string, props: GlueAuthorizationProps = {}) {
    super(scope, id);
    
    const generateCodeArtifactUrl = new sfn.Pass(this, 'GenerateCodeArtifactURL', {
      parameters: {
        'codeartifacturl.$': "States.Format('codeartifact-repository-url-here/', $.taskresult.AuthorizationToken)",
      },
      resultPath: '$.taskresult',
    });
    
  }
};

When I try to use the construct in my stack to create a state machine definition, it returns the following error:

Argument of type 'GlueAuthorization' is not assignable to parameter of type 'IChainable'. Type 'GlueAuthorization' is missing the following properties from type 'IChainable': id, startState, endStates

The error is raised on the line that chains the steps together to create a state machine definition:

const stateMachineDefinition = getAuthorizationToken.next(generateCodeArtifactUrl);

Full code for my stack:

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as sfn from 'aws-cdk-lib/aws-stepfunctions';
import * as tasks from 'aws-cdk-lib/aws-stepfunctions-tasks'
import { GlueAuthorization } from '../lib/glue-authorisation';

export class StepFunctionsStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    # Create first step in state machine.
    const getAuthorizationToken = new tasks.CallAwsService(this, 'GetAuthorizationToken', {
      service: 'codeartifact',
      action: 'getAuthorizationToken',
      iamResources: ['*'],
      parameters: {
        'Domain.$': '$.domain',
        'DomainOwner.$': '$.awsaccountid',
        'DurationSeconds': 900
      },
      resultPath: '$.taskresult',
    });
    
    # Retrieve second step from my construct 'GlueAuthorization'.
    const generateCodeArtifactUrl = new GlueAuthorization(this, 'GlueAuthorization');
    
    # Create the state machine definition by chaining together the two steps.
    const stateMachineDefinition = getAuthorizationToken.next(generateCodeArtifactUrl);
    
    const stateMachine = new sfn.StateMachine(this, 'StateMachine', {
      definitionBody: sfn.DefinitionBody.fromChainable(
        stateMachineDefinition
        ),
        role: stepFunctionRole,
    });
  }
};

I added the IChainable properties to my construct but that doesn't resolve the error:

export interface GlueAuthorizationProps {
  readonly id?: string;
  readonly startState?: sfn.State;
  readonly endStates?: sfn.INextable[];
};

According to the documentation the class Pass implements IChainable, so I'm not sure why I have to do anything further.


Solution

  • The GlueAuthorization class must implement the interface. Add implements sfn.IChainable to the class definition and implement the three properties defined in the interface:

    export class GlueAuthorization extends Construct implements sfn.IChainable {
      public readonly startState: sfn.State;
      public readonly endStates: sfn.INextable[];
      public readonly id: string;
      
      constructor(scope: Construct, id: string, props: GlueAuthorizationProps = {}) {
        super(scope, id);
        
        const generateCodeArtifactUrl = new sfn.Pass(this, 'GenerateCodeArtifactURL', {
          parameters: {
            'codeartifacturl.$': "States.Format('codeartifact-repository-url-here/', $.taskresult.AuthorizationToken)",
          },
          resultPath: '$.taskresult',
        });
    
        this.id = id;
        this.startState = generateCodeArtifactUrl;
        this.endStates = [generateCodeArtifactUrl];
      }
    };