I am trying to create an Azure Function with typescript. I am fairly new to both. I followed the docs and create one Azure function using the steps mentioned in the Azure Docs.
Docs: [Azure function With Typecript](https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-vs-code-typescript?pivots=nodejs-model-v4)
When I created the function using Httptrigger template it worked just fine. I was able to access httptrigger and got the Hello World! in response. I am using programming model v4, host.json v2, Runtime worker: node, worker runtime version is ~4 and node version 20.
My current directory structure is as follows:
az-createquote-functionapp/
├── .vscode/
├── dist/
├── node_modules/
├── src/
│ ├── functions/
│ │ └── createQuoteHttp.ts
│ ├── index.ts
│ └── telemetry.ts
│ ├── processors/
│ │ └── IRequestProcessorInterface.ts
│ │ └── RequestProcessor.ts
├── .gitignore
├── .funcignore
├── eslint.config.js
├── host.json
├── local-settings.json
├── package-lock.json
├── package.json
└── tsconfig.json
My tsconfig.json:
{
"compilerOptions": {
"module": "ESNext",
"target": "ESNext",
"moduleResolution": "Node",
"outDir": "dist",
"rootDir": ".",
"sourceMap": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"noImplicitAny": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true,
},
"include": [
"./**/*.ts",
],
"exclude": [
"node_modules",
"dist"
]
}
My package.json
{
"name": "az-createquote-functionapp",
"version": "1.0.0",
"description": "",
"scripts": {
"build": "tsc",
"watch": "tsc -w",
"clean": "rimraf dist",
"prestart": "npm run clean && npm run build",
"start": "func start --verbose",
"lint": "eslint '**/*.{js,mjs,cjs,ts}'",
"lint:fix": "eslint '**/*.{js,mjs,cjs,ts}' --fix",
"test": "echo \"No tests yet...\""
},
"dependencies": {
"@azure/functions": "^4.5.0",
"@azure/functions-opentelemetry-instrumentation": "^0.1.0",
"@azure/monitor-opentelemetry-exporter": "^1.0.0-beta.24",
"@azure/openapi": "^3.0.104",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/auto-instrumentations-node": "^0.49.1",
"@opentelemetry/exporter-trace-otlp-http": "^0.52.1",
"@opentelemetry/sdk-node": "^0.52.1",
"drizzle-orm": "^0.33.0",
"pg": "^8.12.0"
},
"devDependencies": {
"@eslint/js": "^9.8.0",
"@types/node": "^20.14.15",
"@types/pg": "^8.11.6",
"drizzle-kit": "^0.24.0",
"eslint": "^9.8.0",
"globals": "^15.9.0",
"rimraf": "^5.0.0",
"typescript": "^4.9.5",
"typescript-eslint": "^8.0.0"
},
"overrides": {
"eslint": "^9.8.0"
},
"type": "module",
"main": "dist/src/{index.js,functions/*.js}"
}
My function httptrigger.ts
import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
import { RequestProcessor } from '../processors/RequestProcessor';
export async function createQuoteHttp(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
context.log(`Http function processed request for url "${request.url}"`);
try {
// Use the request processor instance to handle the request
const requestProcessor = new RequestProcessor();
await requestProcessor.process(request, context);
} catch (error : unknown) {
if (error instanceof Error) {
context.log(error.message);
}
}
const name = request.query.get('name') || await request.text() || 'world';
return { body: `Hello, ${name}!` };
};
app.http('createQuoteHttp', {
route: 'V1/createQuote',
methods: ['POST'],
authLevel: 'anonymous',
handler: createQuoteHttp
});
// processors/RequestProcessor.ts
import { HttpRequest, InvocationContext } from '@azure/functions';
import { IRequestProcessorInterface } from './IRequestProcessorInterface';
export class RequestProcessor implements IRequestProcessorInterface {
async process(request: HttpRequest, context: InvocationContext): Promise<void> {
context.log(request.body);
}
}
As soon as I tried to import my processor or any other service as a matter of fact. I start getting following error:
Error [ERR_MODULE_NOT_FOUND]: Worker was unable to load entry point "dist/src/functions/createQuoteHttp.js": Cannot find module '/xxx/yyy/projects/az-createquote-functionapp/dist/src/processors/RequestProcessor' imported from /xxx/yyy/projects/az-createquote-functionapp/dist/src/functions/createQuoteHttp.js
However, files are present in the correct location in the dist folder. Trigger with default template works but as soon as I try to create any directory or other files and import it either in the index.ts or in my trigger.ts. I start getting this error. I need to build lot of files and directories to segregate logics but I am not sure why it is failing.
I have tried changing the node versions, changing the module resolution etc. I am fairly new to both typescript and azure functions. I checked log of documentation and tried to google it but for everyone the error might be the same but issue was always different.
You need to have below codes in the mentioned files.
tsconfig-
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "dist",
"rootDir": ".",
"sourceMap": true,
"strict": false
}
}
package.json-
{
"name": "78860727",
"version": "1.0.0",
"description": "",
"scripts": {
"build": "tsc",
"watch": "tsc -w",
"clean": "rimraf dist",
"prestart": "npm run clean && npm run build",
"start": "func start --verbose",
"test": "echo \"No tests yet...\""
},
"dependencies": {
"@azure/functions": "^4.0.0"
},
"devDependencies": {
"@types/node": "^20.x",
"typescript": "^4.0.0",
"rimraf": "^5.0.0"
},
"main": "dist/src/{index.js,functions/*.js}"
}
RequestProcessor-
import { HttpRequest, InvocationContext } from '@azure/functions';
import { IRequestProcessorInterface } from './IRequestProcessorInterface';
export class RequestProcessor implements IRequestProcessorInterface {
async process(request: HttpRequest, context: InvocationContext): Promise<void> {
const name = await request.query.get('name');
context.log('Response is:', name);
}
}
createQuoteHttp-
import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
import { RequestProcessor } from '../processors/RequestProcessor';
export async function createQuoteHttp(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
context.log(`Http function processed request for url "${request.url}"`);
try {
const requestProcessor = new RequestProcessor();
await requestProcessor.process(request, context);
} catch (error : unknown) {
if (error instanceof Error) {
context.log(error.message);
}
}
const name = await request.text() || await request.json() || 'world';
return { body: `Hello, ${name}!` };
};
app.http('createQuoteHttp', {
route: 'V1/createQuote',
methods: ['POST'],
authLevel: 'anonymous',
handler: createQuoteHttp
});
I am able to get the expected response.
Azure Functions Core Tools
Core Tools Version: 4.0.5907 Commit hash: N/A +807e89766a92b14fd07b9f0bc2bea1d8777ab209 (64-bit)
Function Runtime Version: 4.834.3.22875
[2024-08-13T08:48:56.674Z] Debugger listening on ws://*****/9b7c121***ff0f9
[2024-08-13T08:48:56.676Z] For help, see: https://nodejs.org/en/docs/inspector
[2024-08-13T08:48:56.762Z] Worker process started and initialized.
[2024-08-13T08:48:56.827Z] Debugger attached.
Functions:
createQuoteHttp: [POST] http://localhost:7071/api/V1/createQuote
For detailed output, run func with --verbose flag.
[2024-08-13T08:49:13.411Z] Executing 'Functions.createQuoteHttp' (Reason='This function was programmatically called via the host APIs.', Id=865814c4-1dfa-438d-9396-0f4d9a853e25)
[2024-08-13T08:49:13.546Z] Response is: Afreen
[2024-08-13T08:49:13.546Z] Http function processed request for url "http://localhost:7071/api/V1/createQuote?name=Afreen"
[2024-08-13T08:49:13.575Z] Executed 'Functions.createQuoteHttp' (Succeeded, Id=865814c4-1dfa-438d-9396-0f4d9a853e25, Duration=188ms)
Try to execute the code in debugging mode. Navigate to Run -> click Start debugging