Fixed Docker and tests. Replaced ioredis.

This commit is contained in:
Hackntosh 2023-08-08 19:52:28 -03:00
parent 14e3990d76
commit 4e96576f5d
33 changed files with 1183 additions and 616 deletions

View file

@ -25,7 +25,6 @@ SERVER_PORT=<placeholder>
JWT_ACCESS_SECRET=<placeholder>
# Localstack - The data can be fake (Change this to real data on production)
DOCKER_HOST=unix:///var/run/docker.sock
SERVICES=s3
AWS_ACCESS_KEY_ID=<placeholder>
AWS_SECRET_ACCESS_KEY=<placeholder>

1
.gitignore vendored
View file

@ -9,3 +9,4 @@ dist
pnpm-lock.yaml
package_backup.json
logs/
docker.env

11
.swcrc
View file

@ -7,7 +7,16 @@
"dynamicImport": true
},
"target": "es2020",
"baseUrl": "./"
"baseUrl": "./src",
"paths": {
"clients/*": ["clients/*"],
"config/*": ["config/*"],
"controllers/*": ["controllers/*"],
"interfaces/*": ["interfaces/*"],
"helpers/*": ["helpers/*"],
"middlewares/*": ["middlewares/*"],
"services/*": ["services/*"]
}
},
"exclude": ["@types/", "interfaces/"],
"module": {

View file

@ -23,11 +23,12 @@ RUN npm i pm2 -g
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/prisma ./prisma/
COPY --from=builder /app/dist ./dist/
COPY --from=builder /app/docker.env ./
RUN mv docker.env .env
RUN npm ci
RUN npm run prisma:deploy
EXPOSE 8080
CMD ["npm", "run", "prod:start"]

View file

@ -1,5 +1,10 @@
version: '3.8'
networks:
localstack-net:
name: localstack-net
driver: bridge
services:
postgres:
image: postgres:alpine
@ -8,7 +13,7 @@ services:
ports:
- 5432:5432
env_file:
- .env
- docker.env
volumes:
- postgres:/var/lib/postgresql/data
@ -22,6 +27,24 @@ services:
volumes:
- redis:/data
localstack:
image: localstack/localstack
container_name: localstack_main
restart: unless-stopped
networks:
- localstack-net
ports:
- 4566:4566
- 4572:4572
env_file:
- docker.env
volumes:
- localstack:/data
- '/var/run/docker.sock:/var/run/docker.sock'
volumes:
postgres:
name: backend-db
redis:
driver: local
localstack:

View file

@ -19,7 +19,7 @@ services:
- redis
- localstack
env_file:
- .env
- docker.env
postgres:
image: postgres:alpine
@ -28,7 +28,7 @@ services:
ports:
- 5432:5432
env_file:
- .env
- docker.env
volumes:
- postgres:/var/lib/postgresql/data
@ -42,7 +42,7 @@ services:
- 4566:4566
- 4572:4572
env_file:
- .env
- docker.env
volumes:
- localstack:/data
- '/var/run/docker.sock:/var/run/docker.sock'

30
docker.env.example Normal file
View file

@ -0,0 +1,30 @@
# Environment
NODE_ENV=production
# Postgres config
POSTGRES_DB=<placeholder>
POSTGRES_USER=<placeholder>
POSTGRES_PASSWORD=<placeholder>
DB_HOST=postgres
DATABASE_URL=postgresql://<placeholder>:<placeholder>@${DB_HOST}:<placeholder>/${POSTGRES_DB}?schema=<placeholder>
# Redis
REDIS_HOST=redis
REDIS_PORT=<placeholder>
REDIS_PASSWORD=<placeholder>
# Express
SERVER_PORT=<placeholder>
# Security
JWT_ACCESS_SECRET=<placeholder>
# Localstack - The data can be fake
SERVICES=s3
AWS_ACCESS_KEY_ID=<placeholder>
AWS_SECRET_ACCESS_KEY=<placeholder>
AWS_DEFAULT_REGION=us-east-1
AWS_DEFAULT_OUTPUT=json
AWS_BUCKET=<placeholder>

View file

@ -1,9 +0,0 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
setupFilesAfterEnv: ['<rootDir>/setupTest.ts'],
transform: {
'^.+\\.(t|j)sx?$': '@swc/jest'
}
}

17
jest.config.ts Normal file
View file

@ -0,0 +1,17 @@
import { pathsToModuleNameMapper } from 'ts-jest'
import { compilerOptions } from './tsconfig.json'
import type { JestConfigWithTsJest } from 'ts-jest'
const jestConfig: JestConfigWithTsJest = {
preset: 'ts-jest',
testEnvironment: 'node',
setupFilesAfterEnv: ['<rootDir>/setupTest.ts'],
transform: {
'^.+\\.(t|j)sx?$': '@swc/jest'
},
roots: ['<rootDir>'],
modulePaths: [compilerOptions.baseUrl],
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths)
}
export default jestConfig

1569
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,7 @@
"scripts": {
"build": "swc src -d dist",
"dev:start": "ts-node-dev -r tsconfig-paths/register --transpile-only --respawn src/server.ts",
"docker": "docker compose up -d",
"docker": "docker compose --env-file docker.env up -d",
"docker:build": "docker build -t api . && docker compose up -d",
"docker:db": "docker compose -f docker-compose.db.yml up -d",
"docker:seed": "docker exec -it api npm run prisma:seed",
@ -16,8 +16,7 @@
"prisma:generate": "npx prisma generate",
"prisma:seed": "prisma db seed",
"prisma:studio": "npx prisma studio",
"prisma:deploy": "npx prisma migrate deploy",
"prod:start": "pm2-runtime start dist/server.js",
"prod:start": "npx prisma migrate deploy && pm2-runtime start dist/server.js",
"test": "jest"
},
"ts-standard": {
@ -54,7 +53,7 @@
"eslint-plugin-import": "^2.28.0",
"eslint-plugin-n": "^16.0.1",
"eslint-plugin-promise": "^6.1.1",
"jest": "^29.5.0",
"jest": "^29.6.2",
"nodemon": "^3.0.1",
"pm2": "^4.2.3",
"prettier": "^3.0.0",
@ -80,6 +79,7 @@
"multer": "^1.4.5-lts.1",
"multer-s3": "^3.0.1",
"rate-limit-redis": "^3.0.2",
"redis": "^4.6.7",
"sharp": "^0.32.3",
"socket.io": "^4.7.2",
"validator": "^13.9.0",

View file

@ -1,7 +1,9 @@
import prisma from './src/clients/prisma-client'
import redis from './src/clients/redis-client'
process.env.NODE_ENV = 'development'
afterAll(async () => {
redis.disconnect()
await redis.disconnect()
await prisma.$disconnect()
})

View file

@ -9,6 +9,8 @@ import router from './routes'
const app = express()
// TODO: test socket io, emit notifications when create one.
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(morganMiddleware)
@ -23,7 +25,7 @@ app.use(cors({
app.use((_req, res) => {
res.status(404).json({
error: 'Not found'
error: 'Endpoint not found'
})
})

View file

@ -1,11 +1,24 @@
import RedisClient from 'ioredis'
import logger from 'helpers/logger'
import { createClient, type RedisClientOptions } from 'redis'
const redisPort = parseInt(process.env.REDIS_PORT ?? '6379', 10)
const redisHost = process.env.REDIS_HOST ?? '127.0.0.1'
const redisPassword = process.env.REDIS_PASSWORD ?? ''
const redisHost = process.env.REDIS_HOST ?? ''
const redisPort = process.env.REDIS_PORT ?? ''
const redis = new RedisClient(
`redis://:${redisPassword}@${redisHost}:${redisPort}/0`
)
const redisConfig: RedisClientOptions = {
url: `redis://:${redisPassword}@${redisHost}:${redisPort}/0`
}
const redis = createClient(redisConfig)
redis.connect().then(() => {
logger.info('Successfully connected to Redis')
}).catch((e: Error) => {
logger.error(`Error while connecting to Redis: ${e.message}`)
})
redis.on('error', async (e: Error) => {
logger.error(`Error in Redis client: ${e.message}`)
})
export default redis

View file

@ -10,6 +10,6 @@ const comments = {
fetch: commentFetchController,
fetchLikes: commentFetchLikesController,
update: commentUpdateController
}
} as const
export default comments

View file

@ -10,6 +10,6 @@ const post = {
fetch: postFetchInfoController,
fetchLikes: postFetchLikesController,
update: postUpdateController
}
} as const
export default post

View file

@ -22,6 +22,6 @@ const user = {
signup: userSignupController,
update: userUpdateController,
uploadPicture: userUploadPictureController
}
} as const
export default user

View file

@ -20,8 +20,7 @@ const limiter = rateLimit({
// Store configuration
store: new RedisStore({
// @ts-expect-error - `call` function is not present in @types/ioredis
sendCommand: async (...args: string[]) => await redis.call(...args)
sendCommand: async (...args: string[]) => await redis.sendCommand(args)
})
})

View file

@ -1,7 +1,7 @@
import app from './app'
import { createServer } from 'http'
import logger from 'helpers/logger'
import createSocketIOInstance from 'socket'
import createSocketIOInstance from './socket'
const server = createServer(app)
const io = createSocketIOInstance(server)

View file

@ -10,6 +10,6 @@ const comment = {
fetch: commentFetchService,
fetchLikes: commentFetchLikesService,
update: commentUpdateService
}
} as const
export default comment

View file

@ -10,6 +10,6 @@ const post = {
fetch: postFetchInfoService,
fetchLikes: postFetchLikesService,
update: postUpdateService
}
} as const
export default post

View file

@ -22,6 +22,6 @@ const user = {
signup: userSignupService,
update: userUpdateService,
uploadPicture: userUploadPictureService
}
} as const
export default user

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

View file

@ -2,7 +2,7 @@ import app from '../../app'
import request from 'supertest'
import signUpNewUser from '../utils/create-user'
import deleteUser from '../utils/delete-user'
import type User from '../../interfaces/user'
import type User from 'interfaces/user'
let user: User

View file

@ -2,7 +2,7 @@ import app from '../../app'
import request from 'supertest'
import signUpNewUser from '../utils/create-user'
import deleteUser from '../utils/delete-user'
import type User from '../../interfaces/user'
import type User from 'interfaces/user'
let user: User

View file

@ -2,7 +2,7 @@ import app from '../../app'
import request from 'supertest'
import signUpNewUser from '../utils/create-user'
import deleteUser from '../utils/delete-user'
import type User from '../../interfaces/user'
import type User from 'interfaces/user'
let postId: string

View file

@ -2,7 +2,7 @@ import app from '../../app'
import request from 'supertest'
import signUpNewUser from '../utils/create-user'
import deleteUser from '../utils/delete-user'
import type User from '../../interfaces/user'
import type User from 'interfaces/user'
let user: User

View file

@ -2,7 +2,7 @@ import request from 'supertest'
import app from '../../app'
import deleteUser from '../utils/delete-user'
import signUpNewUser from '../utils/create-user'
import type User from '../../interfaces/user'
import type User from 'interfaces/user'
let user: User
@ -22,7 +22,7 @@ describe('POST /user/auth', () => {
.expect(400)
expect(response.body).toHaveProperty('error')
expect(response.body.error).toBe('User does not exists')
expect(response.body.error).toBe('Invalid email or password')
})
it('should respond with a error if receive an invalid email or password', async () => {

View file

@ -1,7 +1,7 @@
import app from '../../app'
import request from 'supertest'
import signUpNewUser from '../utils/create-user'
import type User from '../../interfaces/user'
import type User from 'interfaces/user'
let user: User

View file

@ -2,7 +2,7 @@ import app from '../../app'
import request from 'supertest'
import deleteUser from '../utils/delete-user'
import signUpNewUser from '../utils/create-user'
import type User from '../../interfaces/user'
import type User from 'interfaces/user'
let user: User

View file

@ -2,7 +2,7 @@ import request from 'supertest'
import app from '../../app'
import deleteUser from '../utils/delete-user'
import signUpNewUser from '../utils/create-user'
import type User from '../../interfaces/user'
import type User from 'interfaces/user'
let user: User

View file

@ -2,7 +2,7 @@ import request from 'supertest'
import app from '../../app'
import signUpNewUser from '../utils/create-user'
import deleteUser from '../utils/delete-user'
import type User from '../../interfaces/user'
import type User from 'interfaces/user'
let user: User

View file

@ -1,46 +1,25 @@
{
"compilerOptions": {
/* Language and Environment */
"target": "es2016",
/* Modules */
"target": "ESNext",
"module": "commonjs",
"rootDir": "./",
"baseUrl": "./src",
"paths": {
"clients/*": [
"clients/*"
],
"config/*": [
"config/*"
],
"controllers/*": [
"controllers/*"
],
"interfaces/*": [
"interfaces/*"
],
"lib/*": [
"lib/*"
],
"middlewares/*": [
"middlewares/*"
],
"services/*": [
"services/*"
],
"clients/*": ["clients/*"],
"config/*": ["config/*"],
"controllers/*": ["controllers/*"],
"interfaces/*": ["interfaces/*"],
"helpers/*": ["helpers/*"],
"middlewares/*": ["middlewares/*"],
"services/*": ["services/*"]
},
"typeRoots": [
"./src/@types",
"./node_modules/@types"
],
/* Emit */
"typeRoots": ["./src/@types", "./node_modules/@types"],
"outDir": "./dist",
"removeComments": true,
/* Interop Constraints */
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
/* Type Checking */
"strict": true,
"skipLibCheck": true
"skipLibCheck": true,
"resolveJsonModule": true
}
}