{"id":25569977,"url":"https://github.com/sandeepls/url-shorten-web","last_synced_at":"2026-03-21T20:30:14.380Z","repository":{"id":277848617,"uuid":"933712816","full_name":"SandeepLS/Url-Shorten-Web","owner":"SandeepLS","description":null,"archived":false,"fork":false,"pushed_at":"2025-02-16T14:47:00.000Z","size":64,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-16T15:34:22.419Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SandeepLS.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-16T14:26:09.000Z","updated_at":"2025-02-16T14:47:03.000Z","dependencies_parsed_at":"2025-02-16T15:44:37.104Z","dependency_job_id":null,"html_url":"https://github.com/SandeepLS/Url-Shorten-Web","commit_stats":null,"previous_names":["sandeepls/url-shorten-web"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SandeepLS%2FUrl-Shorten-Web","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SandeepLS%2FUrl-Shorten-Web/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SandeepLS%2FUrl-Shorten-Web/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SandeepLS%2FUrl-Shorten-Web/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SandeepLS","download_url":"https://codeload.github.com/SandeepLS/Url-Shorten-Web/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239937695,"owners_count":19721483,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-21T00:53:17.567Z","updated_at":"2026-03-21T20:30:14.306Z","avatar_url":"https://github.com/SandeepLS.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"What Will Happen in Our Project?\nUsers log in with Google\nThey send a request with a long URL\nOur backend creates a short URL and returns it\nWhen anyone visits the short URL, they are redirected to the original link\nWe store and track clicks on the short links\n-----------------------------********************-----------------------------------\n\n1. GET request: http://localhost:5000/\n    {\n    \"message\": \"URL Shortener API is running!\"\n    }\n\n2. First, login using: GET http://localhost:5000/auth/google\n   (This will authenticate you in the browser.)\n\n3. Get profile\n   http://localhost:5000/auth/profile\n   Authorization: Bearer YOUR_JWT_TOKEN\n   Response:\n   {\n    \"user\": {\n        \"id\": \"67b1f4c4df4f6b60867b0621\",\n        \"googleId\": \"105319629632544805749\",\n        \"displayName\": \"Sandeep L S\",\n        \"email\": \"sandeepls3025@gmail.com\",\n        \"avatar\": \"https://lh3.googleusercontent.com/a/ACg8ocJMAv-X8ly3Yq-yFOyBPsZM49GciwFRHzz28eb-c4cnUjmFKw=s96-c\"\n    },\n    \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY3YjFmNGM0ZGY0ZjZiNjA4NjdiMDYyMSIsImdvb2dsZUlkIjoiMTA1MzE5NjI5NjMyNTQ0ODA1NzQ5IiwiZGlzcGxheU5hbWUiOiJTYW5kZWVwIEwgUyIsImVtYWlsIjoic2FuZGVlcGxzMzAyNUBnbWFpbC5jb20iLCJhdmF0YXIiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS9BQ2c4b2NKTUF2LVg4bHkzWXEteUZPeUJQc1pNNDlHY2l3RlJIenoyOGViLWM0Y25Vam1GS3c9czk2LWMiLCJpYXQiOjE3Mzk3MTU3ODAsImV4cCI6MTc0MDMyMDU4MH0.zBpPG87bPkO-skiQI3FmnPpOdxhqFyjtwujqnE7AECs\"\n    }\n\n4. Get logout\n   http://localhost:5000/auth/logout\n   Authorization: Bearer YOUR_JWT_TOKEN\n   response:\n   {\n        \"message\": \"Logged out successfully\"\n   }\n\n5. Macking short url:-\n    Method: POST\n    URL: http://localhost:5000/api/shorten\n    Headers:\n    Authorization: Bearer YOUR_JWT_TOKEN\n    Content-Type: application/json\n    Body: { \"originalUrl\": \"https://example.com\" }\n\n    Response is: \n    {\n        \"originalUrl\": \"https://protocoderspoint.com/most-utilized-api-protocal-architecture/\",\n        \"shortUrl\": \"http://localhost:5000/api/urls/fWCMzcrkG\",\n        \"clicks\": 0,\n        \"createdBy\": \"105319629632544805749\",\n        \"topic\": \"Music\",\n        \"_id\": \"67b1ac3ee2385ea192d3db83\",\n        \"createdAt\": \"2025-02-16T09:13:34.213Z\",\n        \"__v\": 0\n    }\n\n6. Redirect Short URL:- if i click the url, Yes it's redirecting.\n    Open http://localhost:5000/abc123 in a browser.\n    It should redirect to https://example.com.\n\n7. Fetch analytics for a specific short URL:-\n    Get: http://localhost:5000/api/urls/analytics/{shortCode}\n    Headers:\n    Authorization: Bearer YOUR_JWT_TOKEN\n    Response: {\n        \"totalClicks\": 3,\n        \"uniqueUsers\": 1,\n        \"clicksByDate\": [\n            {\n                \"date\": \"2025-02-10\",\n                \"clickCount\": 0\n            },\n            {\n                \"date\": \"2025-02-11\",\n                \"clickCount\": 0\n            },\n            {\n                \"date\": \"2025-02-12\",\n                \"clickCount\": 0\n            },\n            {\n                \"date\": \"2025-02-13\",\n                \"clickCount\": 0\n            },\n            {\n                \"date\": \"2025-02-14\",\n                \"clickCount\": 0\n            },\n            {\n                \"date\": \"2025-02-15\",\n                \"clickCount\": 0\n            },\n            {\n                \"date\": \"2025-02-16\",\n                \"clickCount\": 3\n            }\n        ],\n        \"osType\": [\n            {\n                \"osName\": \"Windows\",\n                \"uniqueClicks\": 3\n            }\n        ],\n        \"deviceType\": [\n            {\n                \"deviceName\": \"Desktop\",\n                \"uniqueClicks\": 3\n            }\n        ]\n    }\n\n8. Implementing GET /api/analytics/topic/:topic API\n    Get: http://localhost:5000/api/analytics/topic/:topic\n    Authorization Bearer \n    response:\n    {\n        \"topic\": \"Music\",\n        \"totalClicks\": 3,\n        \"uniqueUsers\": 1,\n        \"clicksByDate\": [\n            {\n                \"date\": \"2025-02-16\",\n                \"totalClicks\": 3\n            }\n        ],\n        \"urls\": [\n            {\n                \"shortUrl\": \"http://localhost:5000/api/urls/fWCMzcrkG\",\n                \"totalClicks\": 3,\n                \"uniqueUsers\": 1\n            }\n        ]\n    }\n\n9. Implement the Overall Analytics API endpoint\n    GET http://localhost:5000/api/analytics/overall\n    Authorization: Bearer \u003cyour_token\u003e\n    response: {\n        \"totalUrls\": 1,\n        \"totalClicks\": 3,\n        \"uniqueUsers\": 1,\n        \"clicksByDate\": [\n            {\n                \"date\": \"2025-02-16\",\n                \"totalClicks\": 3\n            }\n        ],\n        \"osType\": [\n            {\n                \"osName\": \"Windows\",\n                \"uniqueClicks\": 3,\n                \"uniqueUsers\": 1\n            }\n        ],\n        \"deviceType\": [\n            {\n                \"deviceName\": \"Desktop\",\n                \"uniqueClicks\": 3,\n                \"uniqueUsers\": 1\n            }\n        ]\n    }\n\n-------------------------------------------------------\nnpm init -y\nnpm install express mongoose redis dotenv jsonwebtoken passport-google-oauth20 cors rate-limit\nnpm install --save-dev nodemon\nnpm install passport cookie-parser express-session \n\nCookies are a widely used mechanism for storing authentication tokens and maintaining user sessions.\n\nThe SESSION_SECRET is a random secret key used by the express-session middleware to encrypt and sign session data stored in cookies.\n\nWhy is SESSION_SECRET Important?\nSecurity: It prevents session tampering and protects user data.\nIntegrity: Ensures that the session ID is valid and not altered by attackers.\nAuthentication: Required when using session-based authentication\n\nWhat Happens Without SESSION_SECRET?\nSessions won't work properly, and the server might throw an error.\nSession hijacking risk: Without encryption, attackers could manipulate sessions.\nAuthentication failure: Some auth strategies (like Google OAuth) require secure session handling.\n\nHow to Generate a Secure SESSION_SECRET:-\nRun this command in the terminal:\n\u003e node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"\nThis will generate a random 64-character secure key. Use it in your .env file.\n\n-------------------***************************------------------------------\nStep 2: URL Shortening API:-\n\nnpm install shortid valid-url\nnpm i body-parser\n\nshortid → Generates unique short IDs for URLs.\nvalid-url → Validates if a given URL is properly formatted.\n\n1. Create the URL Model\nCreate src/models/Url.js:\n\n2. Create URL Shortening Routes\nCreate src/routes/urlRoutes.js:\n\n3. Create Authentication Middleware\nCreate src/middlewares/authMiddleware.js:\n\n4. Integrate Routes in server.js\nModify src/server.js:\n\nTest URL Shortening API in Postman:-\n1. Macking short url:-\nMethod: POST\nURL: http://localhost:5000/api/shorten\nHeaders:\nAuthorization: Bearer YOUR_JWT_TOKEN\nContent-Type: application/json\nBody: { \"originalUrl\": \"https://example.com\" }\nExpected Response: \n{\n    \"_id\": \"67adbdefa5173ee6cc434c39\",\n    \"originalUrl\": \"https://example.com\",\n    \"shortUrl\": \"http://localhost:5000/Ry-zhD6iL\",\n    \"clicks\": 0,\n    \"createdBy\": \"103014158487352735860\",\n    \"createdAt\": \"2025-02-13T09:39:59.965Z\",\n    \"__v\": 0\n}\n\n2. Redirect Short URL\nOpen http://localhost:5000/abc123 in a browser.\nIt should redirect to https://example.com.\n\n-------------------------------***********************------------------------------------\nTest cases:-\n1. Modularize Business Logic\nMove URL validation and short ID generation into a separate utils file (utils/urlUtils.js).\nExample:\nconst validUrl = require(\"valid-url\");\nconst shortid = require(\"shortid\");\n\nexports.validateUrl = (url) =\u003e validUrl.isUri(url);\nexports.generateShortCode = () =\u003e shortid.generate();\n\n2. Optimize Database Queries\nAdd indexing on frequently queried fields like shortUrl and createdBy to improve performance.\nExample:\nUrlSchema.index({ shortUrl: 1, createdBy: 1 });\n\n3. Improve Error Handling with Middleware\nInstead of wrapping each controller function in a try-catch, create a middleware (middleware/errorHandler.js) to handle errors centrally.\nExample:\nmodule.exports = (err, req, res, next) =\u003e {\n    console.error(err.stack);\n    res.status(500).json({ error: \"Something went wrong\" });\n};\n\nThen, use next(error) in controllers.\n\n4. Enhance Click Analytics for Scalability\nInstead of incrementing clicks synchronously in redirectUrl, use a background queue (e.g., Bull with Redis) to handle updates asynchronously\n\n------------------------------********************************-------------------------------\nStep 3:- Implementing Analytics Tracking for Clicks\n\nNow, we need to track analytics data when a user accesses a short URL. This includes:\n\u003e IP Address\n\u003e User-Agent (browser \u0026 OS info)\n\u003e Device Type (Mobile/Desktop)\n\u003e Timestamp\n\n1. Create a new model: models/Analytics.js\n2. Update URL Controller (controllers/urlController.js)\nModify the redirectUrl function to log analytics.\n\u003e npm install ua-parser-js\n\n3. Testing in Postman\n\u003e Make sure a shortened URL exists (POST /api/shorten)\n\u003e Redirect to a shortened URL (GET /api/urls/{shortUrl})\n\u003e Verify analytics data\n    Connect to MongoDB and check the analytics collection:\n    \u003e db.analytics.find().pretty()\n--------------\nImplementing the API to Fetch URL Analytics:-\n1. Update controllers/urlController.js\n2. Update routes/urlRoutes.js\n3. Testing in postman:\nGet: http://localhost:5000/api/urls/analytics/{shortCode}\nAuthorization Bearer \n\n-------------------------**********************----------------------\nStep 4: Implementing GET /api/analytics/topic/:topic API\n\ncreate analytics Controller (controllers/analytivsController.js)\n\u003e getTopicAnalytics.\n\nThis step will allow users to get analytics for all URLs under a specific topic (e.g., all URLs related to \"Technology\", \"Sports\", etc.)\nTesting in postman:\nGet: http://localhost:5000/api/analytics/topic/:topic\nAuthorization Bearer \n\n-------------------------***********************----------------------\nStep 5. Implement the Overall Analytics API endpoint now. Here’s the plan:\n\u003e Fetch all URLs created by the authenticated user.\n\u003e Aggregate total URLs, total clicks, and unique users.\n\u003e Compute clicks by date, OS type, and device type from analytics data.\n\nupdate analytics Controller (controllers/analytivsController.js)\n\u003e getOverallAnalytics.\n\nTesting in postman:-\nGET http://localhost:5000/api/analytics/overall\nAuthorization: Bearer \u003cyour_token\u003e\n\n-------------------------***********************----------------------\nCaching:\nImplement caching using Redis to store both short and long URLs, improving the performance of the API by reducing database load. Cache data wherever necessary, such as when retrieving URL analytics or redirecting short URLs, to ensure quick access and response times.\n\nCaching Implementation: Use Redis caching to efficiently store and serve short and long URLs.\nTesting \u0026 Error Handling: Write integration tests for all endpoints with comprehensive error handling.\n\nCheck, if the redis is installed in you locall machine or not:\n\u003e redis-server\n\u003e redis-cli ping\n  If Redis is running, you should get a response: PONG\nOR\n\u003e redis-cli\n\u003e ping\n\u003e set\n\n1. redis is installed in you vsCode editor:-\nnpm install redis\n\n2. Create a new file config/redis.js to initialize Redis:\nconfig/redis.js\n\n3. Implement Caching in URL Shortening:\nModify controllers/urlControllers.js to cache shortened URLs.\n(a) Update redirectUrl to use Redis caching:\ncontrollers/urlController.js: redirect\n\n4. Cache Analytics Data\nModify getUrlAnalytics to cache analytics data:\ncontrollers/urlController.js: getUrlAnalytics\n\n5. Step 5: Clear Cache When Data Changes\nWhenever a new short URL is created or analytics data is updated, invalidate the cache.\n(a) Invalidate Cache on New URL Creation\nModify createShorten:\nexports.createShorten = async (req, res) =\u003e {\n    // ... existing code ...\n    \n    const newUrl = await Url.create({ originalUrl, shortUrl, createdBy, topic: topic || \"General\" });\n\n    // Invalidate cache\n    await redisClient.del(`shortUrl:${newUrl.shortUrl}`);\n\n    res.json(newUrl);\n};\n\n(b) Invalidate Cache on New Analytics Entry\nModify redirectUrl\nawait Analytics.create({\n    shortUrl: url.shortUrl,\n    ip: req.ip,\n    userAgent: req.headers[\"user-agent\"],\n    createdAt: new Date(),\n    os,\n    device\n});\n// Invalidate analytics cache\nawait redisClient.del(`analytics:${shortCode}`);\n\n6. Step 6: Write Integration Tests\nYou can use Jest and Supertest to test caching behavior.\n\u003e npm install --save-dev jest supertest\ncreate folder and file, tests/url.test.js:-\nNow, add the following Jest command in package.json:\n\"scripts\": {\n  \"test\": \"jest --runInBand\"\n}\nRun this command: npm test\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsandeepls%2Furl-shorten-web","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsandeepls%2Furl-shorten-web","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsandeepls%2Furl-shorten-web/lists"}