Jeremy
Jeremy

Reputation: 1578

Docker Postgres Prisma Typescript Setup

I have spent AGES trying to get a Docker, Typescript, Postgres, Prisma backend setup working, please help find where i am going wrong! My containers are running, i think my ports are exposed from the API and DB, and thus i should be able to connect / see the graphql panel in my browser on http://0.0.0.0:3000/graphql i.e. the port that is exposed - but no luck!

Dockerfile

FROM node:16-alpine

# Create app directory
WORKDIR /usr/src/app

# copy both to the container
COPY package*.json ./

# install packages to the container
RUN npm install

# copy everything
COPY . .

# generate the prisma database client
RUN npx prisma generate

# expose the api port
EXPOSE 3000

# run the dev app - prod is not currently Dockerised
CMD [ "npm", "run", "dev" ]

docker-compose.yml

version: "3.9"
services:
  api:
    build: .
    container_name: api
    image: api:latest
    volumes:
      - postgres-data:/app/postgres-data
    restart: always
    environment:
      DB_URL: ${DB_URL}
    expose:
      - 3000
    ports:
      - 3000:3000
    depends_on:
      db:
        condition: service_healthy
    command: ["npm", "run", "dev"]

  db:
    container_name: db
    image: postgres:15
    restart: always
    ports:
      - 5432:5432
    expose:
      - 5432
    environment:
      POSTGRES_DB: ${DB_NAME}
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "sh -c 'pg_isready -U ${DB_USER} -d ${DB_NAME}'"]
      interval: 10s
      timeout: 3s
      retries: 3
    volumes:
      - postgres-data:/var/lib/postgresql/data

volumes:
  postgres-data:
    name: postgres-data

You can see here that the ports are ok (i think).

enter image description here

package.json

{
  "name": "budgetappbackend",
  "version": "1.0.0",
  "description": "A typescript and express backend service",
  "main": "dist/index.js",
  "type": "module",
  "scripts": {
    "clean": "rm -rf ./build",
    "compile": "tsc",
    "start": "NODE_ENV=production node ./build/index.js",
    "docker:up": "docker-compose up -d",
    "prebuild": "rm -rf ./build",
    "build": "npm install && npm -s run migrate && npm -s run generate && npm -s run compile",
    "prisma:generate": "npx prisma generate",
    "prisma:migrate": "npx prisma migrate dev",
    "dev": "set NODE_ENV=development && npm install && concurrently npm:dev:*",
    "dev:run": "DOTENV_CONFIG_PATH=.env.development nodemon -r dotenv/config ./src/index.ts",
    "test": "DOTENV_CONFIG_PATH=.env.test jest --setupFiles dotenv/config"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/JRRS1982/BudgetAppBackend.git"
  },
  "engines": {
    "node": "16.15.1"
  },
  "prisma": {
    "schema": "src/Libs/prisma/schema.prisma"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/JRRS1982/BudgetAppBackend/issues"
  },
  "homepage": "https://github.com/JRRS1982/BudgetAppBackend#readme",
  "dependencies": {
    "@apollo/server": "^4.3.2",
    "@prisma/client": "^4.9.0",
    "envalid": "^7.3.1",
    "express": "^4.18.2",
    "graphql": "^16.6.0",
    "graphql-scalars": "^1.20.1",
    "graphql-tag": "^2.12.6"
  },
  "devDependencies": {
    "@faker-js/faker": "^7.6.0",
    "@jest/globals": "^29.4.2",
    "@types/cors": "^2.8.13",
    "@types/jest": "^29.4.0",
    "@types/node": "^18.11.18",
    "concurrently": "^7.6.0",
    "dotenv": "^16.0.3",
    "jest": "^29.4.2",
    "jest-mock-extended": "^3.0.1",
    "nodemon": "^2.0.20",
    "prisma": "^4.9.0",
    "ts-jest": "^29.0.5",
    "ts-node": "^10.9.1",
    "typescript": "^4.9.4"
  }
}

index.ts file

import { ApolloServer } from "@apollo/server";
import { expressMiddleware } from "@apollo/server/express4";
import { ApolloServerPluginDrainHttpServer } from "@apollo/server/plugin/drainHttpServer";
import bodyParser from "body-parser";
import cors from "cors";
import express from "express";
import http from "http";
import { resolvers } from "./resolvers.js";
import { typeDefs } from "./schema.js";
import validateEnv from "./Utils/validateEnv.js";

/**
 * Throw error if we are missing any env variables
 */
validateEnv();

/**
 * Create a server
 */
const app = express();
const httpServer = http.createServer(app);

/**
 * Start server with a plugin to drain server - to shutdown gracefully
 */
const server = new ApolloServer({
  typeDefs,
  resolvers,
  plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});

/**
 * Wait for server to start
 */
await server.start();

/**
 * Add the Apollo server to Express
 */
app.use(cors<cors.CorsRequest>(), bodyParser.json(), expressMiddleware(server));

/**
 * Listen for requests on PORT, or fallback to 4000
 */
await new Promise<void>((resolve) => {
  httpServer.listen({ port: process.env.PORT || 4000 }, resolve);
});

/**
 * Tell the user we are ready
 */
console.log(
  `🚀 Server ready at http://localhost:${process.env.PORT || 4000}/graphql`
);

I am running docker compose up -d --remove-orphans to start the containers

I think this is required, docker exec -it api sh -c "npx prisma migrate dev" to migrate the Prisma schema, but RUN npx prisma generate exists in the Dockerfile to generate the client.

I would like to at least be able to see (the containerised) graphql in the browser (npm run dev will lauch - but not dockerised)?!

I am eager to fix so that the prisma migrations / whatever i am missing happens on the docker compose up -d command (i am also using a makefile for convenience).

The logs here with the up command show that the app is running, but the database is shut down - argh! Help! Thank you.

enter image description here

Upvotes: 0

Views: 1286

Answers (1)

Shane
Shane

Reputation: 26

The log output provided suggests the service is listening on port 3001, but the docker-compose.yml is exposing port 3000.

Aligning these should resolve the issue.

Upvotes: 1

Related Questions