Skip to content

Create transaction API's #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
# CoinFlowSystem

A flexible and secure API-driven coin management system for integrating virtual currency functionality in games and applications.

## Few rules we follow internally

- **Always take input from req.body.input**, Make sure to take and validate input from `req.body.input` and not from `req.body` directly.

## Code Commit Guidelines

When committing code, We follow the following guidelines for commit messages.

```
feat: feature xyz
fix: fix xyz
refactor: refactor xyz
docs: update docs
optimize: optimize xyz
```
4 changes: 4 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
### 1.0.0

- Initial project structure and repo setup
- Initial API's for User, Wallet, and Transaction management
20 changes: 9 additions & 11 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,33 @@ datasource db {
url = env("DATABASE_URL")
}

model User {
model Wallet {
id Int @id @default(autoincrement())
username String @unique
email String @unique
application_user_id String @unique
Wallet Wallet[]
Transaction Transaction[]
created_at DateTime @default(now())
updated_at DateTime @updatedAt
Transaction Transaction[]
}

model Wallet {
model Coin {
id Int @id @default(autoincrement())
user_id Int
user User @relation(fields: [user_id], references: [id])
balance Int
Transaction Transaction[]
name String
symbol String
created_at DateTime @default(now())
updated_at DateTime @updatedAt
Transaction Transaction[]
}

model Transaction {
id Int @id @default(autoincrement())
transaction_type String
user_id Int
user User @relation(fields: [user_id], references: [id])
wallet_id Int
wallet Wallet @relation(fields: [wallet_id], references: [id])
coin_id Int
amount Int
created_at DateTime @default(now())
updated_at DateTime @updatedAt
wallet Wallet @relation(fields: [wallet_id], references: [id])
coin Coin @relation(fields: [coin_id], references: [id])
}
2 changes: 1 addition & 1 deletion src/utils/middlewares.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const validateUserExistsSentThroughReqBody = function (path: any) {
return async function (req: any, res: any, next: any) {
let user = await prisma.user.findUnique({
where: {
id: get(req, path, null),
id: parseInt(get(req, path, null)),
},
});
if (user === null) {
Expand Down
105 changes: 60 additions & 45 deletions src/v1/routes.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,68 @@
import { middlewareValidateYupSchemaAgainstReqBody, validateUserExistsSentThroughReqBody } from "../utils/middlewares";
import { createUserSchema, updateUserSchema } from "./user.validation";
import { createUser, getUserBalance, updateUser } from "./user";
import { createWalletSchema, updateWalletSchema } from "./wallet/wallet.validation";
import { createWallet, updateWallet, getWalletBalance } from "./wallet/wallet";

import express from "express";
import {
createTransaction,
deleteTransaction,
getTransaction,
getTransactions,
getTransactionsByUser,
updateTransaction,
} from "./transactions/transaction";
import { createTransactionSchema, updateTransactionSchema } from "./transactions/transaction.validation";

const v1Routes = express.Router();
v1Routes.get("/createTransaction", function (req, res) {
res.status(200).json({
message: "createTransaction",
});
});
v1Routes.get("/updateTransaction", function (req, res) {
res.status(200).json({
message: "updateTransaction",
});
});
v1Routes.delete("/deleteTransaction", function (req, res) {
res.status(200).json({
message: "deleteTransaction",
});
});
v1Routes.get("/getTransaction", function (req, res) {
res.status(200).json({
message: "getTransaction",
});
});
v1Routes.get("/getTransactions", function (req, res) {
res.status(200).json({
message: "getTransactions",
});
});
v1Routes.get("/getTransactionsByUser", function (req, res) {
res.status(200).json({
message: "getTransactionsByUser",
});
});

v1Routes.post("/createWallet", function (req, res) {
res.status(200).json({
message: "createWallet",
});
});

v1Routes.post("/createUser", middlewareValidateYupSchemaAgainstReqBody(createUserSchema), createUser);

/**
* Wallet Apis Start
*/

v1Routes.post("/createWallet", middlewareValidateYupSchemaAgainstReqBody(createWalletSchema), createWallet);
v1Routes.put(
"/updateUser",
validateUserExistsSentThroughReqBody("body.input.id"),
middlewareValidateYupSchemaAgainstReqBody(updateUserSchema),
updateUser,
"/updateWallet",
validateUserExistsSentThroughReqBody("body.id"),
middlewareValidateYupSchemaAgainstReqBody(updateWalletSchema),
updateWallet,
);
v1Routes.get("/getWalletBalance", validateUserExistsSentThroughReqBody("body.input.id"), getWalletBalance);

/**
* Wallet Apis End
*/

/**
* Transaction Apis Start
* */

v1Routes.post(
"/createTransaction",
validateUserExistsSentThroughReqBody("body.user_id"),
middlewareValidateYupSchemaAgainstReqBody(createTransactionSchema),
createTransaction,
);
v1Routes.get("/getUserBalance", validateUserExistsSentThroughReqBody("body.input.id"), getUserBalance);

v1Routes.put(
"/updateTransaction/:id",
validateUserExistsSentThroughReqBody("body.user_id"),
middlewareValidateYupSchemaAgainstReqBody(updateTransactionSchema),
updateTransaction,
);

v1Routes.delete("/deleteTransaction/:id", deleteTransaction);

v1Routes.get("/getTransaction/:id", getTransaction);

v1Routes.get("/getTransactions", getTransactions);

v1Routes.get(
"/getTransactionsByUser/:userId",
validateUserExistsSentThroughReqBody("params.userId"),
getTransactionsByUser,
);
/**
* Transaction Apis End
*/

export default v1Routes;
6 changes: 0 additions & 6 deletions src/v1/transaction.ts

This file was deleted.

145 changes: 145 additions & 0 deletions src/v1/transactions/transaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import prisma from "../../database/prisma";
import { Response, Request } from "express";
import { generateError } from "../../utils/errors";

export const createTransaction = async (req: Request, res: Response) => {
try {
// Check if wallet_id exists
const wallet = await prisma.wallet.findUnique({
where: { id: req.body.input.wallet_id },
});
if (!wallet) {
return res.status(400).json({ message: "Wallet not found" });
}

// Create transaction
let response = await prisma.transaction.create({
data: req.body.input,
});

res.status(200).json({
message: "Transaction created successfully",
user: response,
});
} catch (e) {
generateError(res, e);
}
};

export const updateTransaction = async (req: Request, res: Response) => {
try {
const { id } = req.params;
const updateData = req.body.input;

// Check if transaction exists
const existingTransaction = await prisma.transaction.findUnique({
where: { id: parseInt(id) },
});
if (!existingTransaction) {
return res.status(404).json({ message: "Transaction not found" });
}

if (updateData.wallet_id) {
const wallet = await prisma.wallet.findUnique({
where: { id: existingTransaction.wallet_id },
});
if (!wallet) {
return res.status(400).json({ message: "Wallet not found" });
}
}

// Update the transaction
const updatedTransaction = await prisma.transaction.update({
where: { id: parseInt(id) },
data: updateData,
});

res.status(200).json({
message: "Transaction updated successfully",
transaction: updatedTransaction,
});
} catch (e) {
generateError(res, e);
}
};

export const deleteTransaction = async (req: Request, res: Response) => {
try {
const { id } = req.params;

// Check if the transaction exists
const existingTransaction = await prisma.transaction.findUnique({
where: { id: parseInt(id) },
});
if (!existingTransaction) {
return res.status(404).json({ message: "Transaction not found" });
}

// Delete the transaction
await prisma.transaction.delete({
where: { id: parseInt(id) },
});

res.status(200).json({ message: "Transaction deleted successfully" });
} catch (e) {
generateError(res, e);
}
};

export const getTransaction = async (req: Request, res: Response) => {
try {
const { id } = req.params;

// Retrieve the transaction
const transaction = await prisma.transaction.findUnique({
where: { id: parseInt(id) },
});

if (!transaction) {
return res.status(404).json({ message: "Transaction not found" });
}

res.status(200).json(transaction);
} catch (e) {
generateError(res, e);
}
};

export const getTransactions = async (req: Request, res: Response) => {
try {
const transactions = await prisma.transaction.findMany();

if (!transactions) {
return res.status(404).json({ message: "Transactions not found" });
}

res.status(200).json(transactions);
} catch (e) {
generateError(res, e);
}
};

export const getTransactionsByUser = async (req: Request, res: Response) => {
try {
const { userId } = req.params;

// Check if user exists
const user = await prisma.user.findUnique({
where: { id: parseInt(userId) },
});

// Retrieve transactions for the user
const transactions = await prisma.transaction.findMany({
where: {
user_id: user?.id,
},
});

res.status(200).json({
transactions: transactions,
message: "Transactions retrieved successfully",
});
} catch (e) {
generateError(res, e);
}
};
29 changes: 29 additions & 0 deletions src/v1/transactions/transaction.validation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { object, string, number, InferType, date } from "yup";

export const createTransactionSchema = object({
transaction_type: string()
.required("Transaction type is required")
.oneOf(["credit", "debit"], "Transaction type must be either credit or debit"),
wallet_id: number()
.required("Wallet ID is required")
.positive("Wallet ID must be a positive integer")
.integer("Wallet ID must be an integer"),
amount: number()
.required("Amount is required")
.positive("Amount must be a positive integer")
.integer("Amount must be an integer"),
created_at: date()
.default(() => new Date())
.required("Creation date is required"),
updated_at: date()
.default(() => new Date())
.required("Update date is required"),
});
export type CreateTransactionSchema = InferType<typeof createTransactionSchema>;

export const updateTransactionSchema = object({
id: number().required("ID is required"),
transaction_type: string().optional().oneOf(["credit", "debit"], "Transaction type must be either credit or debit"),
amount: number().optional().positive("Amount must be a positive integer").integer("Amount must be an integer"),
});
export type UpdateTransactionSchema = InferType<typeof updateTransactionSchema>;
1 change: 0 additions & 1 deletion src/v1/wallet.ts

This file was deleted.

Loading