Skip to content

Commit e8e44fc

Browse files
committed
chore(): Readme improvment and refactor
1 parent ca155fc commit e8e44fc

File tree

9 files changed

+117
-11
lines changed

9 files changed

+117
-11
lines changed

.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
PORT=3000
2+
BASE_URL=http://localhost:3000
3+
AWS_REGION=eu-south-1
4+
LINKS_TABLE_NAME=links
5+
CACHE_TTL=60

README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,54 @@
11
# SHORTEN
2+
23
Simple shortener service with DynamoDB, Express and nanoid.
4+
5+
Features:
6+
7+
- DynamoDB with AWS SDK as database provider (no configuration)
8+
- Create (same api for update) short URL
9+
- Delete short URL
10+
- Swagger documentation
11+
- Clustering mode (for high traffic)
12+
- Redirects
13+
- Caching for redirects on memory with custom TTL
14+
- Rate limit on apis
15+
- Error handling
16+
- Compression response with gzip
17+
- nanoID generator
18+
19+
## Start
20+
21+
```bash
22+
git clone <repo>
23+
cd <repo>
24+
yarn install
25+
yarn start
26+
```
27+
28+
## Development
29+
30+
```bash
31+
git clone <repo>
32+
cd <repo>
33+
yarn install
34+
yarn start:dev
35+
```
36+
37+
## Cluster start
38+
39+
```bash
40+
git clone <repo>
41+
cd <repo>
42+
yarn install
43+
yarn start:cluster
44+
```
45+
46+
TODO:
47+
48+
- Authentication with API Key for POST/DELETE/PUT
49+
- Add readble slug for short URL optional parameter
50+
- Add domain on model, to manage multiple domains
51+
- Manage wrapper to run on Lambda AWS
52+
- Add analytics for short URL
53+
- Add auto exctract short slug from redirect url
54+
- Add another provider for database (Redis, MongoDB, Firebase(?))>

package-lock.json

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
"@types/cors": "^2.8.12",
3535
"@types/express": "^4.17.13",
3636
"@types/morgan": "^1.9.3",
37+
"@types/nanoid": "^3.0.0",
3738
"@types/node": "^18.6.2",
39+
"@types/node-cache": "^4.2.5",
3840
"@types/swagger-ui-express": "^4.1.3",
3941
"cpy-cli": "^4.1.0",
4042
"nodemon": "^2.0.19",

src/controllers/links.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@ import { Request, Response } from "express";
33
import { CacheContainer } from "node-ts-cache";
44
import { param } from "express-validator";
55
import swaggerUi from "swagger-ui-express";
6+
import { env } from "process";
67

78
import { putLink, getLink, deleteLink } from "../services/links";
89

910
import { ILink } from "../models/ILink";
1011

1112
const { linksDocs } = require("../../docs/links.doc");
1213

14+
const CACHE_TTL: any = parseInt(env.CACHE_TTL as string) || 60;
15+
1316
export default class LinksController {
1417
private cacheNode;
1518

@@ -43,7 +46,7 @@ export default class LinksController {
4346
public insertLink = async (req: Request, res: Response) => {
4447
const { body: link } = req;
4548
const createdLink = (await putLink(link)) as ILink;
46-
await this.cacheNode.setItem(createdLink.slug, null, { ttl: 60 });
49+
await this.cacheNode.setItem(createdLink.slug, null, { ttl: CACHE_TTL });
4750
res.json(createdLink);
4851
};
4952

src/libs/cache.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { MemoryStorage } from "node-ts-cache-storage-memory";
33

44
const NodeCache = require("node-cache");
55
new NodeCache();
6+
67
const linksCache = new CacheContainer(new MemoryStorage());
78

89
export default linksCache;

src/libs/ddbClient.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
22

33
if (!process.env.AWS_REGION) {
4-
throw new Error("AWS_REGION is not set");
4+
throw new Error("AWS_REGION is not set on .env file");
55
}
66

77
export const ddbClient = new DynamoDBClient({ region: process.env.AWS_REGION });

src/libs/ddbDocClient.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ const unmarshallOptions = {
1212
};
1313

1414
const translateConfig = { marshallOptions, unmarshallOptions };
15-
const ddbDocClient = DynamoDBDocumentClient.from(ddbClient, translateConfig);
15+
const db = DynamoDBDocumentClient.from(ddbClient, translateConfig);
1616

17-
export { ddbDocClient };
17+
export { db };

src/services/links.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import { PutCommand, GetCommand, DeleteCommand } from "@aws-sdk/lib-dynamodb";
2-
import { ddbDocClient } from "../libs/ddbDocClient";
2+
import { db } from "../libs/ddbDocClient";
3+
34
import { ILink, ILinkDTO } from "../models/ILink";
45

6+
//FIX: Strange import bug
57
const { nanoid } = require("nanoid");
6-
const TABLE_NAME = "links";
8+
9+
const TABLE_NAME = process.env.LINKS_TABLE_NAME || "links";
710
const BASE_PATH = process.env.BASE_URL;
811

912
export const putLink = async ({ redirect, slug }: ILinkDTO) => {
@@ -21,7 +24,7 @@ export const putLink = async ({ redirect, slug }: ILinkDTO) => {
2124
};
2225

2326
try {
24-
await ddbDocClient.send(new PutCommand(params));
27+
await db.send(new PutCommand(params));
2528
return newLink;
2629
} catch (err) {
2730
console.error(err);
@@ -36,9 +39,9 @@ export const getLink = async (slug: string): Promise<ILink | undefined> => {
3639
},
3740
};
3841
try {
39-
const data = await ddbDocClient.send(new GetCommand(params));
40-
const link: ILink = data.Item as ILink;
41-
return link;
42+
return (await (
43+
await db.send(new GetCommand(params))
44+
).Item) as ILink;
4245
} catch (err) {
4346
console.error(err);
4447
}
@@ -52,7 +55,7 @@ export const deleteLink = async (slug: string) => {
5255
},
5356
};
5457
try {
55-
await ddbDocClient.send(new DeleteCommand(params));
58+
await db.send(new DeleteCommand(params));
5659
return { message: "Link deleted", status: "success" };
5760
} catch (err) {
5861
console.error(err);

0 commit comments

Comments
 (0)