Introduction#

GitHub this note shows

  • Next.js 13 api route handler
  • AWS SDK S3Client and PollyClient
  • Deploy with Amplify hosting
  • TODO: add cognito authentication

Setup Project#

Create a new Next.js project with latest Next.js version

npx create-app-next@latest

Install AWS SDK for S3 and Polly

npm install @aws-sdk/client-s3 @aws-sdk/polly-client

Install other dependencies, here is details of package.json file

{
"name": "nextjs-polly-demo",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@aws-sdk/client-polly": "^3.344.0",
"@aws-sdk/client-s3": "^3.344.0",
"@types/node": "20.2.5",
"@types/react": "18.2.8",
"@types/react-dom": "18.2.4",
"autoprefixer": "10.4.14",
"axios": "^1.4.0",
"eslint": "8.41.0",
"eslint-config-next": "13.4.4",
"next": "13.4.4",
"postcss": "8.4.24",
"react": "18.2.0",
"react-dom": "18.2.0",
"tailwindcss": "3.3.2",
"typescript": "5.1.3",
"uuid": "^9.0.0"
},
"devDependencies": {
"@types/uuid": "^9.0.1"
}
}

API Route Handler#

Project structure for api route handler

|--app
|--api
|--polly
|--route.ts
|--polly
|--page.tsx
|--global.css
|--layout.tsx
|--page.tsx
|--public
|--test.mp3
|--package.json
|--.eslint.json
|--next.config.js
|--tailwind.config.js
|--tsconfig.json

Create a simple api handler (POST, and GET). This is very usefull

  • Run at server side
  • Call AWS services such as S3, Polly

The GET method

export async function GET(request: Request) {
console.log("server receive get ", request);
return NextResponse.json({ name: "haimtran get" });
}

The POST method

export async function POST(request: Request) {
const requestJson = await request.json();
// call polly api here
return NextResponse.json({ url: name });
}

Polly Client#

Let try S3 client first, detail here

import { ListObjectsCommand, S3Client } from "@aws-sdk/client-s3";
const s3Client = new S3Client({
region: "us-east-1",
// TODO: credentials via cogito identity pool id
});
// desconstruct input
const listObject = async ({ bucketName }: { bucketName: string }) => {
try {
const res = await s3Client.send(
new ListObjectsCommand({
Bucket: bucketName,
})
);
console.log(res);
} catch (error) {
console.log(error);
}
};

Then let create a Polly client

const pollyClient = new PollyClient({
region: "ap-southeast-1",
// TODO: credentials via cogito identity pool id
});
const synthesizeSpeed = async ({ message }: { message: string }) => {
const response = await pollyClient.send(
new SynthesizeSpeechCommand({
Engine: "standard",
LanguageCode: "en-US",
OutputFormat: "mp3",
Text: message,
VoiceId: "Amy",
})
);

Synthesize speech from text, and save the Audio Stream output to a file

const audio = await response.AudioStream?.transformToByteArray();
if (audio?.buffer) {
fs.writeFileSync("hello.mp3", Buffer.from(audio.buffer));
} else {
console.log("error audio buffer");
}
// TODO write to S3
if (response.AudioStream) {
const blob = new Blob([response.AudioStream as Blob]);
const url = URL.createObjectURL(blob);
console.log(url);
}

Troubleshooting#

Please pay attention to the function format, correct one is

export async function GET(request: Request) {
console.log("server receive get ", request);
return NextResponse.json({ name: "haimtran get" });
}

Wrong one

export async function GET({ request }: { request: Request }) {
console.log("server receive get ", request);
return NextResponse.json({ name: "haimtran get" });
}