jAntoni
jAntoni

Reputation: 621

Function with Typescript and Prisma doesn't get loaded in Azure

I have a Yoga-GraphQL API server application written in typescript using VS Code.

My application uses Prisma client for database model.

When I run my application locally it works perfectly fine. When I deploy the code to Azure Function (tried Consumption plan or Flex Consumption) it is not loading the function.

What I have tried

On my analysis I have found that if the function code calls the database it is giving an error. I have confirmed this by hardcoding the database variables.

A part of my package.json is given below. I have tried troubleshooting from Azure Function portal and Application Insights. I haven't got any clue that works.

I feel I'm missing to fire prisma generate while deploying to Azure via VS Code. Any help on this is greatly appreciated.

{
  "$schema": "https://json.schemastore.org/package",
  "name": "api-gateway",
  "version": "1.0.0",
  "description": "GraphQL API Gateway",
  "main": "dist/src/functions/*.js",
  "scripts": {
      "build": "npm run compile && npm run prisma:generate",
      "check:all": "concurrently npm:check:pretty npm:check:lint npm:check:type",
      "check:lint": "eslint .",
      "check:pretty": "prettier --check .",
      "check:type": "tsc --noEmit",
      "clean": "rimraf dist",
      "compile": "tsc",
      "dev": "NODE_ENV=development tsx watch --clear-screen=false src/main.ts",
      "doc:graphql:generate": "magidoc generate",
      "doc:graphql:preview": "magidoc preview --port 4100",
      "lint-staged": "lint-staged",
      "local": "tsx src/main.ts",
      "prepare": "husky",
      "prisma:db:pull": "prisma db pull",
      "prisma:db:seed": "prisma db seed",
      "prisma:generate": "prisma generate",
      "prisma:migrate:dev": "prisma migrate dev --name",
      "prestart": "npm run clean && npm run build",
      "start": "func start",
      "start-v": "npm run clean && npm run build && func start --verbose",
      "pretest": "npm run check:all && npm run build",
      "test": "echo \"Tests are not implemented yet\"",
      "tscc": "tsc --showConfig",
      "watch": "tsc -w",
      "postinstall": "prisma generate" 
  },

Update

In Flex Consumption Plan (Linux) I am able to see the function loaded but it shows error as below enter image description here

Update 2

Code as reply This is my schema.prisma

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["multiSchema"]
}

generator pothos {
  provider = "prisma-pothos-types"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
  schemas  = ["product", "matr"]
}

model Address {
  id              Int               @id @default(autoincrement())
  addressLine1    String            @db.Text
  ...

  @@schema("product")
}

model Contact {
  id                     Int               @id @default(autoincrement())
  contactId           String?
  accountId           String?
...
  @@schema("product")
}

Below is my structure of Function App (Ver 4) showing the code in index.ts

My http trigger function code is

    import { createYoga } from 'graphql-yoga'
import { InvocationContext, HttpRequest, HttpResponseInit, app } from '@azure/functions'
import { schema } from '../schema'

/**
 * Create the Graphql-Yoga server
 */
const yoga = createYoga({
  graphqlEndpoint: '/graphql',
  schema: schema,
  graphiql: true,
})

/**
 * Create the handler for Azure function
 *
 * @param req The request object
 * @param context The context object
 *
 * @returns The response object
 */
const httpTrigger1 = async function (
  req: HttpRequest,
  context: InvocationContext,
): Promise<HttpResponseInit> {
  //  Invoke the Graphql server
  const response = await yoga.fetch(req.url, {
    method: req.method?.toString(),
    body: req.body,
    headers: req.headers as HeadersInit,
  })

  const responseHeaders = Object.fromEntries(response.headers.entries())

  // Log the response details
  context.log('Response Headers:', responseHeaders)

  const responseText = await response.text()

  //  Prepare the response object and send back
  return {
    status: response.status,
    body: responseText,
    headers: responseHeaders,
  }
}

/**
 * Set the configuration for the Azure function
 */
app.http('graphql', {
  methods: ['POST', 'GET'],
  authLevel: 'anonymous',
  handler: httpTrigger1,
})

export { httpTrigger1 }

Upvotes: 0

Views: 259

Answers (1)

Ikhtesam Afrin
Ikhtesam Afrin

Reputation: 6487

I have followed this document to use Prisma in Azure typescript V4 function and I did following steps to achieve it.

  1. Executed npm install @prisma @prisma/client and then npx prisma init in the terminal which created .env and the schema.prisma file.
  2. Provided the correct connection string of postgres database in .env file.
  3. Then executed npx prisma generate command which created Prisma client libraries in a separate folder named Prisma. I am using all the default code here.
  4. I have the given folder structure and below codes in the mentioned files.
|   .env
|   .funcignore
|   .gitignore
|   host.json
|   local.settings.json
|   package-lock.json
|   package.json
|   tsconfig.json
|
+---.vscode
|       extensions.json
|       launch.json
|       settings.json
|       tasks.json
|
+---dist
|   \---src
|       |   index.js
|       |   index.js.map
|       |
|       \---functions
|               httpTrigger1.js
|               httpTrigger1.js.map
|
+---node_modules
|
+---prisma
|   |   schema.prisma
|   |
|   \---client
|       |   default.d.ts
|       |   default.js
|       |   edge.d.ts
|       |   edge.js
|       |   index-browser.js
|       |   index.d.ts
|       |   index.js
|       |   package.json
|       |   query_engine-windows.dll.node
|       |   schema.prisma
|       |   wasm.d.ts
|       |   wasm.js
|       |
|       \---runtime
|               edge-esm.js
|               edge.js
|               index-browser.d.ts
|               index-browser.js
|               library.d.ts
|               library.js
|               react-native.js
|               wasm.js
|
\---src
    |   index.ts
    |
    \---functions
            httpTrigger1.ts

httpTrigger1.ts -

import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
import { PrismaClient } from '@prisma/client';  

const prisma = new PrismaClient();

interface TodoRequestBody {
    todo: string;
}

export async function httpTrigger1(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
    context.log(`HTTP function processed request for URL "${request.url}"`);

    try {
        const body = await request.json() as TodoRequestBody;
        
        if (body && body.todo) {
            const todo = body.todo;
            const item = await prisma.todo.create({
                data: { todo }
            });

            return {
                status: 200,
                jsonBody: item
            };
        } else {
            return {
                status: 400,
                body: "Please pass a todo in the request body"
            };
        }
    } catch (error) {
        context.log(error);

        return {
            status: 500,
            body: "An error occurred on the server"
        };
    }
}

app.http('httpTrigger1', {
    methods: ['POST'],
    authLevel: 'anonymous',
    handler: httpTrigger1
});

schema.prisma -

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model todo {
  completed Boolean? @default(false)
  id        Int      @default(autoincrement()) @id
  todo      String
}

package.json-

{
  "name": "79045076",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "clean": "rimraf dist",
    "prestart": "npm run clean && npm run build",
    "start": "func start",
    "test": "echo \"No tests yet...\""
  },
  "dependencies": {
    "@azure/functions": "^4.0.0",
    "@prisma/client": "^5.20.0"
  },
  "devDependencies": {
    "@types/node": "^20.x",
    "prisma": "^5.20.0",
    "rimraf": "^5.0.0",
    "typescript": "^4.0.0"
  },
  "main": "dist/src/{index.js,functions/*.js}"
}
  1. I have added DATABASE_URL in App settings of function app.

enter image description here

  1. I have used both npx func azure functionapp publish {functionAppName} command and the deploy to Azure Function option present in the Workspace of vs code in order to deploy this function to a Linux Consumption plan Function App. Make sure you are getting the trigger endpoint post successful deployment.

enter image description here

I am able to create a record in the database successfully.

enter image description here

Upvotes: 0

Related Questions