Skip to content

wendeee/scissor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

41 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

A Backend API for a URL Shortner (Snipit)

Snipit is a URL Shortener API. Snipit allows you shorten long URLs, customize links, and generate qrcode for shortned links. This API was built by Chinwendu Enyinna using JavaScript-based server side technologies. This API follows the REST architectural design pattern.


Contributors Forks Stargazers Issues Linkedin Badge Twitter Badge AltSchool Badge


Technologies used

NodeJS Express.js TypeScript Postgres JWT


Requirements

The following are the requirements I implemented in this project πŸ‘‡:
  • Users should be able to sign up(register) and sign in into their account

  • For the URL Shortener functionality, users should be able to:

    • Shorten a long url

    • Customize their short url using a custom name. This is particularly beneficial for small SMEs as it helps promote their brand.

    • Generate QRCodes for their shortened URLS. Users can download the QR code image and use it in their promotional materials or/and on their website.

    • Track their shortened URL's performance

    • See the history of links they’ve created so they can easily find and reuse links they have previously created.



Development

Prerequisites

Clone this repo

 git clone https://github.com/wendeee/scissor.git

Install project dependencies

npm install

Update .env with example.env

  • Sign up on Cloudinary to get API_KEY for free and other details needed in your .env file
  • To implement forgot password and reset password functionality, I used Nodemailer and mail trap to send reset token to user's email.

Run development server

npm run dev

Models


User

field data_type constraints
name string required
email string required
password string required
confirmPassword string required
confirmationCode string added dynamically
provider string added dynamically

URLService

field data_type constraints
longURL string required
shortURL string added dynamically
createdBy string referenced
UrlCode string added dynamically
customName string added dynamically
clicks number updated dynamically
qrcodeurl string addedynamically
clickHistory sring Array required

OTP

field data_type constraints
email string required
generatedFor string(uuid) referenced
otp string required
createdAt Date required
expiresAt Date required

API Endpoints

Base URL

USERS

Register/Sign up a user

  • Route: /api/v1/auth/signup

  • method: POST

  • πŸ‘‡: Body

{
  "name": "Jackson",
  "email": "jackson@gmail.com",
  "password": "jackson12345",
  "confirmPassword": "jackson12345"
}

πŸ‘‡: Response

{
  "data": {
    "modifiedResponse": {
      "id": "d983edfc-31d7-47f3-971f-bc3ec6fbd1d5",
      "provider": "email",
      "status": "Pending",
      "name": "Jackson",
      "email": "jackson@gmail.com",
      "confirmationCode": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6eyJlbWFpbCI6ImRldmJhYnl3ZW5kZWVlQGdtYWlsLmNvbSJ9LCJpYXQiOjE2ODgxMDQ5MjIsImV4cCI6MTY4ODEwODUyMn0.6Nc_evPpN9eW75PTzfd29CUth3RADHZpo470jkPuCxA",
      "updatedAt": "2023-06-30T06:02:02.019Z",
      "createdAt": "2023-06-30T06:02:02.019Z"
    }
  },
  "status": 200,
  "message": [
    {
      "type": "success",
      "content": "User has been successfully registered. Please confirm your email."
    }
  ]
}

Login/Sign in a user

Route: /api/auth/login method: POST

πŸ‘‡: Body

{
  "email": "jackson@gmail.com",
  "password": "jackson12345"
}

πŸ‘‡: Response

{
  "data": {
    "modifiedResponse": {
      "id": "d983edfc-31d7-47f3-971f-bc3ec6fbd1d5",
      "name": "Jackson",
      "email": "jackson@gmail.com",
      "provider": "email",
      "status": "Pending",
      "confirmationCode": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6eyJlbWFpbCI6ImRldmJhYnl3ZW5kZWVlQGdtYWlsLmNvbSJ9LCJpYXQiOjE2ODgxMDQ5MjIsImV4cCI6MTY4ODEwODUyMn0.6Nc_evPpN9eW75PTzfd29CUth3RADHZpo470jkPuCxA",
      "createdAt": "2023-06-30T06:02:02.019Z",
      "updatedAt": "2023-06-30T06:02:02.019Z"
    },
    "jwtToken": {
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImQ5ODNlZGZjLTMxZDctNDdmMy05NzFmLWJjM2VjNmZiZDFkNSIsImlhdCI6MTY4ODEwNTAwOCwiZXhwIjoxNjg4MTA4NjA4fQ.2qrIJhJmm9PtZjrvSTDS0PRzmvzP_O5MlAq0G38ng6k"
    }
  },
  "status": 200,
  "message": []
}

Forgot Password

  • Route: /api/v1/auth/forgotPassword
  • Method: POST

πŸ‘‡: Body

{
  "email": "jackson@gmail.com"
}

πŸ‘‡: Response

{
  "status": "success",
  "message": "An OTP token has been sent to your email"
}

URL

Shorten a URL

  • Route: api/v1/url
  • Method: POST
  • Header
  • Authorization: Bearer {token}

πŸ‘‡: Body

{
  "longURL": "https://www.amazon.com/Too-Late-Definitive-Colleen-Hoover/dp/1538756595/ref=zg_bs_g_books_sccl_1/139-5024682-0087834?psc=1",
  "customName": "book"
}

πŸ‘‡: Response

{
   "data": {
        "customUrl": {
            "id": "94f85561-c46d-457a-8b0d-e5b2654871f3",
            "clicks": 0,
            "longURL": "https://www.amazon.com/Too-Late-Definitive-Colleen-Hoover/dp/1538756595/ref=zg_bs_g_books_sccl_1/139-5024682-0087834?psc=1",
            "shortURL": "https://snipit.onrender.com/book",
            "UrlCode": "book",
            "createdBy": "3dabcdc5-eb77-4198-874e-f597d1153908",
            "clickHistory": [],
            "updatedAt": "2023-07-03T09:13:47.086Z",
            "createdAt": "2023-07-03T09:13:47.086Z",
            "customName": null,
            "qrcodeurl": null
        }
    },
    "status": 200,
    "message": [
        {
            "type": "success",
            "content": "Short URL created!"
        }
    ]
}

//Shortening a URL without a custom name
{
    "data": {
        "customUrl": {
            "id": "80c6cc7e-7080-4e30-afed-7841371db20c",
            "clicks": 0,
            "longURL": "https://www.amazon.com/Atomic-Habits-Proven-Build-Break/dp/0735211299/ref=zg_bs_g_books_sccl_4/139-5024682-0087834?psc=1",
            "shortURL": "https://snipit.onrender.com/_JKNjM",
            "UrlCode": "_JKNjM",
            "createdBy": "3dabcdc5-eb77-4198-874e-f597d1153908",
            "clickHistory": [],
            "updatedAt": "2023-07-03T09:19:44.194Z",
            "createdAt": "2023-07-03T09:19:44.194Z",
            "customName": null,
            "qrcodeurl": null
        }
    },
    "status": 200,
    "message": [
        {
            "type": "success",
            "content": "Short URL created!"
        }
    ]
}

//shortening a URL that has already been cached
{
   "data": {
        "customUrl": "https://snipit.onrender.com/_JKNjM"
    },
    "status": 200,
    "message": [
        {
            "type": "success",
            "content": "ShortUrl generated successfully!!"
        }
    ]
}

Generate QRCode for short URL

  • Route: /api/v1/url/qrcode
  • Method: POST
  • Header
  • Authorization: Bearer {token}

πŸ‘‡: Body

{
  "shortURL": "https://snipit.onrender.com/_JKNjM"
}

πŸ‘‡: Response

{
  "data": {
    "url": "https://snipit.onrender.com/_JKNjM",
    "qrCodeImageUrl": "https://res.cloudinary.com/dwsbmjhzd/image/upload/v1688376327/qrcodes/dxtapjl1ptuigkfn0jil.png"
  },
  "status": 200,
  "message": [
    {
      "type": "success",
      "content": "QRCode generated!"
    }
  ]
}

Get Generated Link History

  • Route: /api/v1/url/history
  • Method: GET
  • Header
  • Authorization: Bearer {token}

πŸ‘‡: Response

{
  "data": {
    "generatedShortUrl": [
      {
        "shortURL": "https://snipit.onrender.com/_JKNjM",
        "longURL": "https://www.amazon.com/Atomic-Habits-Proven-Build-Break/dp/0735211299/ref=zg_bs_g_books_sccl_4/139-5024682-0087834?psc=1",
        "numberOfClicksOnShortUrl": 1,
        "clickLocation": [
          {
            "location": "Oregon, United States",
            "timestamp": "2023-07-03T09:29:24.118Z"
          }
        ],
        "id": "80c6cc7e-7080-4e30-afed-7841371db20c",
        "qrcodeurl": "https://res.cloudinary.com/dwsbmjhzd/image/upload/v1688376327/qrcodes/dxtapjl1ptuigkfn0jil.png",
        "clicks": 1,
        "createdat": "2023-07-03T09:19:44.194Z"
      },

      {
        "shortURL": "https://snipit.onrender.com/book",
        "longURL": "https://www.amazon.com/Too-Late-Definitive-Colleen-Hoover/dp/1538756595/ref=zg_bs_g_books_sccl_1/139-5024682-0087834?psc=1",
        "numberOfClicksOnShortUrl": 0,
        "clickLocation": [],
        "id": "94f85561-c46d-457a-8b0d-e5b2654871f3",
        "qrcodeurl": null,
        "clicks": 0,
        "createdat": "2023-07-03T09:13:47.086Z"
      },

      {
        "shortURL": "https://snipit.onrender.com/ZIvwUi",
        "longURL": "https://www.amazon.com/Atomic-Habits-Proven-Build-Break/dp/0735211299/ref=zg_bs_g_books_sccl_4/139-5024682-0087834?psc=1",
        "numberOfClicksOnShortUrl": 0,
        "clickLocation": [],
        "id": "6e6679d5-05a2-430e-8275-a0373039f7ef",
        "qrcodeurl": null,
        "clicks": 0,
        "createdat": "2023-07-03T09:22:02.399Z"
      }
    ],
    "shortUrlCount": 3,
    "QRCodeCount": 1
  },
  "status": 200,
  "message": [
    {
      "type": "success",
      "content": "URL history retrieved!"
    }
  ]
}

Lessons I learned while working on this:

  • Writing Nodejs with Typescript
  • Working with Postgresql

Contact

Project Link: https://github.com/wendeee/scissor

Acknowledgments

About

URL-shortner service

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published