Skip to content

Commit

Permalink
Merge pull request #76 from MurakawaTakuya/feat/72-api-put-delete
Browse files Browse the repository at this point in the history
APIにPUT,DELETEを作成した
  • Loading branch information
MurakawaTakuya authored Dec 1, 2024
2 parents 25dcb88 + 7c3a5a2 commit c19f895
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 28 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ API is provided by Firebase Cloud Functions. Database is provided by Firestore.
- Body
- name: string
- streak?: number
- example
- Example
```json
{
"name": "testUser",
Expand Down Expand Up @@ -147,7 +147,7 @@ the same as Get User Data by User Id
- userId: string
- deadline: Date
- text: string
- example
- Example
```json
{
"userId": "IK0Zc2hoUYaYjXoqzmCl",
Expand Down
18 changes: 3 additions & 15 deletions functions/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
/**
* Import function triggers from their respective submodules:
*
* import {onCall} from "firebase-functions/v2/https";
* import {onDocumentWritten} from "firebase-functions/v2/firestore";
*
* See a full list of supported triggers at https://firebase.google.com/docs/functions
*/

import cors from "cors";
import express from "express";
import rateLimit from "express-rate-limit";
Expand All @@ -16,9 +7,6 @@ import { onRequest } from "firebase-functions/v2/https";
import helmet from "helmet";
import serviceAccount from "./serviceAccountKey.json";

// Start writing functions
// https://firebase.google.com/docs/functions/typescript

admin.initializeApp({
credential: admin.credential.cert(serviceAccount as admin.ServiceAccount),
storageBucket: "todo-real-c28fa.appspot.com",
Expand All @@ -33,15 +21,15 @@ app.use(express.json());
// 10分間で最大300回に制限
app.use(
rateLimit({
windowMs: 5 * 60 * 1000,
windowMs: 10 * 60 * 1000,
max: 1000,
})
);
// 1時間で最大1000回に制限
app.use(
rateLimit({
windowMs: 10 * 60 * 1000,
max: 20,
windowMs: 60 * 60 * 1000,
max: 1000,
})
);

Expand Down
51 changes: 48 additions & 3 deletions functions/src/routers/goalRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interface Goal {
}

// GET: 全ての目標を取得
router.route("/").get(async (req: Request, res: Response) => {
router.get("/", async (req: Request, res: Response) => {
try {
const goalSnapshot = await db.collection("goal").get();
if (goalSnapshot.empty) {
Expand All @@ -30,7 +30,7 @@ router.route("/").get(async (req: Request, res: Response) => {
});

// GET: userIdから目標を取得
router.route("/:userId").get(async (req: Request, res: Response) => {
router.get("/:userId", async (req: Request, res: Response) => {
const userId = req.params.userId;

if (!userId) {
Expand Down Expand Up @@ -59,7 +59,7 @@ router.route("/:userId").get(async (req: Request, res: Response) => {
});

// POST: 新しい目標を作成
router.route("/").post(async (req: Request, res: Response) => {
router.post("/", async (req: Request, res: Response) => {
const goalId = db.collection("goal").doc().id; // FirebaseのドキュメントIDを生成

let userId: Goal["userId"];
Expand Down Expand Up @@ -97,4 +97,49 @@ router.route("/").post(async (req: Request, res: Response) => {
}
});

// PUT: 目標を更新
router.put("/:goalId", async (req: Request, res: Response) => {
const goalId = req.params.goalId;
const { userId, deadline, text }: Partial<Goal> = req.body;

if (!userId && !deadline && !text) {
return res.status(400).json({
message: "At least one of userId, deadline, or text is required",
});
}

const updateData: Partial<Omit<Goal, "deadline">> & {
deadline?: admin.firestore.Timestamp;
} = {}; // 型エラーが出たため書き方変更
if (userId) updateData.userId = userId;
if (deadline)
updateData.deadline = admin.firestore.Timestamp.fromDate(
new Date(deadline)
);
if (text) updateData.text = text;

try {
await db.collection("goal").doc(goalId).update(updateData);
return res.json({ message: "Goal updated successfully", goalId });
} catch (error) {
return res.status(500).json({ message: "Error updating goal", error });
}
});

// DELETE: 目標を削除
router.delete("/:goalId", async (req: Request, res: Response) => {
const goalId = req.params.goalId;

if (!goalId) {
return res.status(400).json({ message: "Goal ID is required" });
}

try {
await db.collection("goal").doc(goalId).delete();
return res.json({ message: "Goal deleted successfully", goalId });
} catch (error) {
return res.status(500).json({ message: "Error deleting goal", error });
}
});

export default router;
41 changes: 41 additions & 0 deletions functions/src/routers/postRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,45 @@ router.post("/", async (req: Request, res: Response) => {
}
});

// PUT: 投稿を更新
router.put("/:postId", async (req: Request, res: Response) => {
const postId = req.params.postId;
const { userId, storeId, text, goalId }: Partial<Post> = req.body;

if (!userId && !storeId && !text && !goalId) {
return res
.status(400)
.json({ message: "At least one field is required to update" });
}

const updateData: Partial<Post> = {};
if (userId) updateData.userId = userId;
if (storeId) updateData.storeId = storeId;
if (text) updateData.text = text;
if (goalId) updateData.goalId = goalId;

try {
await db.collection("post").doc(postId).update(updateData);
return res.json({ message: "Post updated successfully", postId });
} catch (error) {
return res.status(500).json({ message: "Error updating post", error });
}
});

// DELETE: 投稿を削除
router.delete("/:postId", async (req: Request, res: Response) => {
const postId = req.params.postId;

if (!postId) {
return res.status(400).json({ message: "Post ID is required" });
}

try {
await db.collection("post").doc(postId).delete();
return res.json({ message: "Post deleted successfully", postId });
} catch (error) {
return res.status(500).json({ message: "Error deleting post", error });
}
});

export default router;
51 changes: 45 additions & 6 deletions functions/src/routers/userRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface User {
}

// GET: 全てのユーザーデータを取得(アカウント機能を作成したら廃止)
router.route("/").get(async (req: Request, res: Response) => {
router.get("/", async (req: Request, res: Response) => {
try {
const userSnapshot = await db.collection("user").get();

Expand All @@ -30,7 +30,7 @@ router.route("/").get(async (req: Request, res: Response) => {
});

// GET: userIdからユーザー情報を取得
router.route("/id/:userId").get(async (req: Request, res: Response) => {
router.get("/id/:userId", async (req: Request, res: Response) => {
const userId = req.params.userId;

if (!userId) {
Expand All @@ -49,7 +49,7 @@ router.route("/id/:userId").get(async (req: Request, res: Response) => {
});

// GET: userNameからユーザー情報を取得
router.route("/name/:userName").get(async (req: Request, res: Response) => {
router.get("/name/:userName", async (req: Request, res: Response) => {
const userName = req.params.userName;

if (!userName) {
Expand All @@ -74,7 +74,7 @@ router.route("/name/:userName").get(async (req: Request, res: Response) => {
});

// POST: 新しいユーザーを登録
router.route("/").post(async (req: Request, res: Response) => {
router.post("/", async (req: Request, res: Response) => {
let name: User["name"];
let uid: string;
let streak: User["streak"];
Expand All @@ -85,8 +85,8 @@ router.route("/").post(async (req: Request, res: Response) => {
return res.status(400).json({ message: "Invalid request body", error });
}

if (!name || !uid || streak === undefined) {
return res.status(400).json({ message: "name and streak are required" });
if (!name || !uid) {
return res.status(400).json({ message: "name and uid are required" });
}

// 既に同じ名前のuserが存在する場合はエラーを返す
Expand All @@ -111,6 +111,45 @@ router.route("/").post(async (req: Request, res: Response) => {
}
});

// PUT: ユーザー情報を更新
router.put("/:userId", async (req: Request, res: Response) => {
const userId = req.params.userId;
const { name, streak }: Partial<User> = req.body;

if (!name && streak === undefined) {
return res
.status(400)
.json({ message: "At least one of name or streak is required" });
}

const updateData: Partial<User> = {};
if (name) updateData.name = name;
if (streak !== undefined) updateData.streak = streak;

try {
await db.collection("user").doc(userId).update(updateData);
return res.json({ message: "User updated successfully", userId });
} catch (error) {
return res.status(500).json({ message: "Error updating user", error });
}
});

// DELETE: ユーザーを削除
router.delete("/:userId", async (req: Request, res: Response) => {
const userId = req.params.userId;

if (!userId) {
return res.status(400).json({ message: "User ID is required" });
}

try {
await db.collection("user").doc(userId).delete();
return res.json({ message: "User deleted successfully", userId });
} catch (error) {
return res.status(500).json({ message: "Error deleting user", error });
}
});

export default router;

// ユーザー名からユーザー情報を取得
Expand Down
3 changes: 2 additions & 1 deletion src/Components/PostForm/PostForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ export default function PostForm() {
}

setProgress(100); // アップロード完了の進捗を表示
console.log("success:", postData);
const data = await response.json();
console.log("Success:", data);
} catch (err) {
setError("データの送信に失敗しました");
console.error(err);
Expand Down
1 change: 0 additions & 1 deletion src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export default function Top() {
return (
<>
<Posts />
asdf
<PostForm />
<GoalModal />
<Button variant="contained" onClick={requestPermission}>
Expand Down

0 comments on commit c19f895

Please sign in to comment.