Skip to content

🔄 Migration Guide: acai-js to acai-ts

Acai-TS is a complete TypeScript rewrite of acai-js with improved type safety, decorator support, and modern ES6+ features. This guide will help you migrate your existing acai-js code to acai-ts.

Quick Start

The main changes are:

  1. Install acai-ts and reflect-metadata
  2. Convert JavaScript to TypeScript
  3. Update imports to use ES6 modules
  4. Add type annotations
  5. Use decorators for cleaner endpoint definitions (optional)

ðŸ“Ķ Installation Changes

Before (acai-js)

1
npm install acai-js

After (acai-ts)

1
npm install acai-ts reflect-metadata

New Requirements: - Node.js >= 18.18.2 - TypeScript >= 5.0 - reflect-metadata package (for decorator support)

📂 Import Changes

Before (acai-js)

1
const { Router, Event } = require('acai-js');

After (acai-ts)

1
2
3
import 'reflect-metadata';
import { Router, Event } from 'acai-ts';
import { APIGatewayProxyEvent, DynamoDBStreamEvent } from 'aws-lambda';

🔧 TypeScript Configuration

Add to your tsconfig.json:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "target": "ES2020",
    "module": "commonjs",
    "moduleResolution": "node",
    "esModuleInterop": true
  }
}

🌐 APIGateway Router Changes

Before (acai-js)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const { Router } = require('acai-js');

exports.handler = async (event) => {
  const router = new Router({
    basePath: '/api/v1',
    schemaPath: './openapi.yml'
  });

  return await router.route(event);
};

After (acai-ts)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import 'reflect-metadata';
import { Router } from 'acai-ts';
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';

export const handler = async (
  event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> => {
  const router = new Router({
    basePath: '/api/v1',
    schemaPath: './openapi.yml'
  });

  return await router.route(event);
};

ðŸŽŊ Endpoint Changes

Pattern-Based (File-Based) Routing

Before (acai-js)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// users.js
exports.requirements = {
  post: {
    requiredBody: 'CreateUserRequest'
  }
};

exports.post = async (request, response) => {
  response.body = { id: '123', ...request.body };
  return response;
};

After (acai-ts)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// users.ts
import { Request, Response } from 'acai-ts';

export const requirements = {
  post: {
    requiredBody: 'CreateUserRequest'
  }
};

export const post = async (
  request: Request, 
  response: Response
): Promise<Response> => {
  response.body = { id: '123', ...request.body };
  return response;
};

ðŸŽĻ Decorator-Based Routing (NEW in acai-ts!)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// File: src/handlers/users.ts
import { BaseEndpoint, Validate, Response, Request } from 'acai-ts';

export class UsersEndpoint extends BaseEndpoint {
  @Validate({ requiredBody: 'CreateUserRequest' })
  async post(request: Request, response: Response): Promise<Response> {
    response.body = { id: '123', ...request.body };
    return response;
  }
}

🗃ïļ Event Handler Changes

📊 DynamoDB Streams

Before (acai-js)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const { Event } = require('acai-js');

exports.handler = async (event) => {
  const dynamodb = new Event(event, {
    operations: ['INSERT', 'MODIFY']
  });

  for (const record of dynamodb.records) {
    console.log(record.newImage);
  }
};

After (acai-ts)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import { Event } from 'acai-ts';
import { DynamoDBStreamEvent } from 'aws-lambda';

export const handler = async (event: DynamoDBStreamEvent): Promise<void> => {
  const dynamodb = new Event(event, {
    operations: ['INSERT', 'MODIFY']
  });

  for (const record of dynamodb.records) {
    console.log(record.newImage);
  }
};

ðŸĻĢ S3 Events

Before (acai-js)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const { Event } = require('acai-js');

exports.handler = async (event) => {
  const s3Event = new Event(event, {
    getObject: true,
    isJSON: true
  });

  await s3Event.process();

  for (const record of s3Event.records) {
    console.log(record.body);
  }
};

After (acai-ts)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import { Event } from 'acai-ts';
import { S3Event } from 'aws-lambda';

export const handler = async (event: S3Event): Promise<void> => {
  const s3Event = new Event(event, {
    getObject: true,
    isJSON: true
  });

  await s3Event.process();

  for (const record of s3Event.records) {
    console.log(record.body);
  }
};

📎 SQS Messages

Before (acai-js)

1
2
3
4
5
6
7
8
9
const { Event } = require('acai-js');

exports.handler = async (event) => {
  const sqsEvent = new Event(event);

  for (const record of sqsEvent.records) {
    console.log(record.body);
  }
};

After (acai-ts)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import { Event } from 'acai-ts';
import { SQSEvent } from 'aws-lambda';

export const handler = async (event: SQSEvent): Promise<void> => {
  const sqsEvent = new Event(event);

  for (const record of sqsEvent.records) {
    console.log(record.body);
  }
};

📝 Logger Changes

Before (acai-js)

1
2
global.logger.info('message');
global.logger.error('error');

After (acai-ts)

1
2
3
4
import { Logger } from 'acai-ts';

Logger.info('message');
Logger.error('error');

âœĻ New Features in acai-ts

1ïļâƒĢ Decorator Support

Use decorators for cleaner endpoint definitions:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// File: src/handlers/users.ts
import { BaseEndpoint, Validate, Before, After, Timeout, Request, Response } from 'acai-ts';

const authMiddleware = async (request: Request, response: Response) => {
  // Auth logic
};

const loggingMiddleware = async (request: Request, response: Response) => {
  // Logging logic
};

export class UsersEndpoint extends BaseEndpoint {
  @Validate({ requiredBody: 'CreateUserRequest' })
  @Before(authMiddleware)
  @After(loggingMiddleware)
  @Timeout(30000)
  async post(request: Request, response: Response): Promise<Response> {
    // Clean business logic
    response.body = { id: '123', ...request.body };
    return response;
  }
}

2ïļâƒĢ Full TypeScript Type Safety

All classes, interfaces, and functions are fully typed:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import { Request, Response } from 'acai-ts';

const request: Request = {
  path: '/users',
  method: 'POST',
  body: { email: 'user@example.com' },
  headers: {},
  queryParameters: {},
  pathParameters: {}
};

3ïļâƒĢ Custom Data Classes with Types

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
interface UserData {
  id: string;
  email: string;
}

class User {
  id: string;
  email: string;

  constructor(record: any) {
    this.id = record.body.id;
    this.email = record.body.email;
  }

  sendWelcomeEmail(): void {
    // Type-safe method
  }
}

const dynamodb = new Event<User>(event, {
  dataClass: User,
  operations: ['INSERT']
});

for (const user of dynamodb.records) {
  user.sendWelcomeEmail(); // Fully typed!
}

4ïļâƒĢ Improved Error Handling

1
2
3
import { ApiError } from 'acai-ts';

throw new ApiError('User not found', 404, 'user_id');

🔁 API Compatibility

Most APIs remain compatible, but with added type safety:

acai-js acai-ts Notes
Router Router Same API, now typed
Event Event Same API, now typed
Request RequestClient / Request Typed interface
Response ResponseClient / Response Typed interface
global.logger Logger Import from package

⚠ïļ Breaking Changes

1. Package Name

  • Old: acai-js or @syngenta-digital/Acai
  • New: acai-ts

2. Node.js Version

  • Old: Node 10.10+
  • New: Node 18.18.2+

3. File Extensions

  • Old: .js files
  • New: .ts files

4. Export Syntax

  • Old: exports.handler
  • New: export const handler

5. Import Syntax

  • Old: require()
  • New: import statements

✅ Migration Checklist

  • [ ] Install acai-ts and reflect-metadata
  • [ ] Update tsconfig.json with decorator support
  • [ ] Convert .js files to .ts
  • [ ] Change require() to import statements
  • [ ] Change exports. to export const
  • [ ] Add AWS Lambda event types
  • [ ] Add type annotations to functions
  • [ ] Update acai-js imports to acai-ts
  • [ ] Add import 'reflect-metadata' at entry points
  • [ ] Test all endpoints and event handlers
  • [ ] Update deployment configuration for TypeScript build

🆘 Need Help?