aws-cloudformation / cloudformation-cli-typescript-plugin

The CloudFormation Provider Development Toolkit Node.js Plugin allows you to autogenerate TypeScript code based on an input schema.
Apache License 2.0
45 stars 15 forks source link

Migrate away from class-transfomer #100

Open RichiCoder1 opened 1 year ago

RichiCoder1 commented 1 year ago

This is a rethought version of my previous ticket https://github.com/aws-cloudformation/cloudformation-cli-typescript-plugin/issues/68

To resummarize the issues with class-transformer:

The updated proposal proposes swapping class-transformer with three components:

While a very large change, it would uncouple this plugin from TypeScript and an unmaintained library while hopefully simplifying the Dev UX of developing a resource in typescript.

For example, a simple handler like the template default would become (example greatly appreviated):

// handlers.ts
import { Resource, TypeConfiguration } from "./.generated/models";
import { createResource, ProgressEvent, exceptions } from '@amazon-web-services-cloudformation/cloudformation-cli-typescript-lib';

const { entrypoint, testEntrypoint } = createResource<Resource, TypeConfiguration>({
    typeName: Resource.TypeName,
    schema: Resource.Schema,
    // Type information for all the below is automatically infered
    async create({ session, properties, request, logger, typeConfiguration }) {
        // Example:
        try {
            const { apiKey } = typeConfiguration;
            const response = await fetch(`https://api.someservice.com`, {
              method: 'POST',
              headers: { 'x-api-key': apiKey },
              body: { ...properties },
            });
            const { id } = await response.json();
            properties.id = id;
            // else handle error
        } catch(err) {
            logger.log(err);
            // exceptions module lets CloudFormation know the type of failure that occurred
            throw new exceptions.InternalFailure(err.message);
            // this can also be done by returning a failed progress event
            // return ProgressEvent.failed(HandlerErrorCode.InternalFailure, err.message);
        }
        return properties;
    },
    /* more handlers.... */
    async list({ properties, typeConfiguration }) {
       /* ...some list code... */
       // Just return a plain array of models, validate via typescript & ajv
       return [/* list of plain old javascript models */];
    },
});

export { entrypoint, testEntrypoint };

This also externalizes a lot of concerns unnecessary to the user code, infers a lot more of type information automatically, and makes developing resource types much less mentally onerous allowing developers to focus on business logic.

It would require more work with the SDK and generated code however.

RichiCoder1 commented 1 year ago

I've got a basic PoC branch moving now: https://github.com/aws-cloudformation/cloudformation-cli-typescript-plugin/compare/master...RichiCoder1:cloudformation-cli-typescript-plugin:feat/drop_decorators?expand=1

Ended up using AJV via a some superset tools called typeconv and suretype which provide schema generate and validation respectively.

Validated that this gets us validation and rich type information, and using camelcase-keys gets us the nice, typescript-y experience.

What I'm working on now is:

I might honestly end up making a completely clean fork for the plugin as it'll be a major API change from the current state of this plugin.