-
-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d4ca000
commit 02746d5
Showing
11 changed files
with
282 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
meta { | ||
name: Create New Link | ||
type: http | ||
seq: 2 | ||
} | ||
|
||
post { | ||
url: http://localhost:5050/api/v1/links | ||
body: json | ||
auth: none | ||
} | ||
|
||
body:json { | ||
{ | ||
"longUrl": "http://github.com/HelloWorld", | ||
"customCode": "hiii" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"version": "1", | ||
"name": "kzilla.xyz", | ||
"type": "collection", | ||
"ignore": [ | ||
"node_modules", | ||
".git" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,47 @@ | ||
// controller functions | ||
import type { Context } from "hono"; | ||
import { createLinkSchema } from "../models/links"; | ||
import { createLink, fetchLink } from "../services/link-service"; | ||
import { generateRandomCode } from "../utils/links"; | ||
import { BackendError } from "../utils/errors"; | ||
import { getConnInfo } from "@hono/node-server/conninfo"; | ||
|
||
/** | ||
@summary Validates the request body and creates a new link | ||
*/ | ||
export async function handleCreateLink(c: Context) { | ||
const ipAddress = getConnInfo(c).remote.address || "::1"; | ||
const reqBody = await c.req.json(); | ||
const { longUrl, customCode } = await createLinkSchema.parseAsync(reqBody); | ||
|
||
let shortCode = customCode ?? generateRandomCode(6); | ||
let analyticsCode = generateRandomCode(6); | ||
let linkId = generateRandomCode(12); | ||
|
||
const shortCodeConflict = await fetchLink(shortCode, analyticsCode, linkId); | ||
|
||
if (shortCodeConflict) { | ||
if (customCode && shortCodeConflict.customCode === customCode) { | ||
throw new BackendError("CONFLICT", { | ||
message: "CUSTOM_CODE_CONFLICT", | ||
details: "The custom url you provided already exists", | ||
}); | ||
} | ||
|
||
// TODO: possiblity of bad practice here... check later | ||
console.log("DEBUG: Conflicts occured, retrying"); | ||
shortCode = generateRandomCode(6); | ||
analyticsCode = generateRandomCode(6); | ||
linkId = generateRandomCode(12); | ||
} | ||
|
||
const createLinkRes = await createLink( | ||
longUrl, | ||
shortCode, | ||
analyticsCode, | ||
linkId, | ||
ipAddress, | ||
); | ||
|
||
console.log(createLinkRes); | ||
return c.json({ message: "Link created successfully" }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { z } from "zod"; | ||
|
||
export const linkSchema = z.object({ | ||
linkId: z.string().min(10), | ||
clicks: z.number().default(0), | ||
analyticsCode: z.string().trim().min(5), | ||
longUrl: z.string().url().trim().min(5), | ||
customCode: z.string().trim().min(4).max(25).optional(), | ||
creatorIpAddress: z.string().ip().optional().default("::1"), | ||
logs: z | ||
.array( | ||
z.object({ | ||
ipAddress: z.string().ip(), | ||
timestamp: z.number(), | ||
}), | ||
) | ||
.optional(), | ||
// * This naming is followed to keep it backward compatible don't try to improve it Lol' | ||
enabled: z.boolean().default(true), | ||
timestamp: z.date().default(new Date()), | ||
}); | ||
|
||
export const createLinkSchema = linkSchema.pick({ | ||
longUrl: true, | ||
customCode: true, | ||
}); | ||
|
||
export type LinkSchemaType = z.infer<typeof linkSchema>; | ||
export type CreateLinkSchemaType = z.infer<typeof createLinkSchema>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,12 @@ | ||
import { Hono } from 'hono'; | ||
import linkRouter from './links-router'; | ||
import { Hono } from "hono"; | ||
import linkRouter from "./link-router"; | ||
|
||
const appRouter = new Hono(); | ||
|
||
appRouter.route('/links', linkRouter); | ||
appRouter.get("/", (c) => { | ||
return c.text("Hello World!"); | ||
}); | ||
|
||
appRouter.route("/links", linkRouter); | ||
|
||
export default appRouter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { Hono } from "hono"; | ||
import { handleCreateLink } from "../controllers/links-controller"; | ||
|
||
const linkRouter = new Hono(); | ||
|
||
// linkRouter.get("/me", handleFetchMyLinks); | ||
// linkRouter.get("/:shortCode", handleFetchLink); | ||
|
||
linkRouter.post("/", handleCreateLink); | ||
|
||
// linkRouter.put("/", handleUpdateLink); | ||
// linkRouter.put("/flush", handleFlushLinks); | ||
|
||
export default linkRouter; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import type { LinkSchemaType } from "../models/links"; | ||
import db from "../utils/db"; | ||
import { BackendError } from "../utils/errors"; | ||
|
||
export async function fetchLink( | ||
shortCode: string, | ||
analyticsCode?: string, | ||
linkId?: string, | ||
) { | ||
try { | ||
const linksCollection = (await db()).collection<LinkSchemaType>("links"); | ||
|
||
return await linksCollection.findOne({ | ||
shortCode, | ||
analyticsCode, | ||
linkId, | ||
}); | ||
} catch (err) { | ||
throw new BackendError("INTERNAL_ERROR", { | ||
message: "Error while fetch a link", | ||
details: err, | ||
}); | ||
} | ||
} | ||
|
||
export async function createLink( | ||
longUrl: string, | ||
shortCode: string, | ||
analyticsCode: string, | ||
linkId: string, | ||
ipAddress: string, | ||
) { | ||
const linksCollection = (await db()).collection<LinkSchemaType>("links"); | ||
|
||
return await linksCollection.insertOne({ | ||
linkId, | ||
longUrl, | ||
customCode: shortCode, | ||
analyticsCode, | ||
clicks: 0, | ||
creatorIpAddress: ipAddress, | ||
enabled: true, | ||
timestamp: new Date(), | ||
logs: [], | ||
}); | ||
} |
Oops, something went wrong.