Skip to content

anshulnegitc/url-shortener-app-backend

Repository files navigation

Url Shortener Application

It's an imitation of Url Shortener Service.

Only functional requirements are considered while developing this project i.e to generate short url and redirect short url to original url.

In case url got expired/moved to other domain/not responsding, a 404 error page is shown.

Redis is used as primary as well as caching database here.

Some analytics and expression values(like,star,thumbs up etc...) are permanently stored in database while urls are short lived.

Application Architecture. Application-Architrecture

Desktop View. Img-1

404 Page. Img-2

Analytics. Img-4

Mobile View. Img-3

Overview video

Here's a short video that explains the project and how it uses Redis:

Url Shortener

How it works

How the data is stored:

  • Urls.
    • It maps the long_url with short_url.
    • short_url is base62 value of counter and is indexed.
    • Expiration of 30 mins is set.
    • Data is stored as
class Url extends Entity { }
const urlSchema = new Schema(Url, {
    long_url: { type: 'string' },
    short_url: { type: 'string', indexed: true }
});
client.execute(['EXPIRE', `Url:EntityId`, 1800]);
  • Range.
    • It's a key-value pair to store the current range of counter, initialise at the first time with 1,00,000.
    • And gets incremented by 1,00,000 after every server restart/crash.
client.execute(['SET', 'range', 100000]);
client.execute(['INCRBY','range', 100000]);
  • Counter.
    • Stores the expression(visitor count,links redirected,links generated, heart,like and star).
    • It permanently stores data and increment the count on respective operation.
      • As total visitor to a website is stored as {entityId:"something",name:'visitor',count:2}
      • And so on for every count on website.
class Counter extends Entity { }
const counterSchema = new Schema(Counter, {
    name: { type: 'string', indexed: true },
    count: { type: 'number' },
});
counterEntity = await CounterRepository().fetch(id);
counterEntity.entityData.count += 1;
CounterRepository().save(counterEntity);
  • Continent.
    • Stores continent wise analytics on the website.
    • It permanently stores data and increment the count of the fields on respective operation.
    • On respective operation continent name is fetched and incremented the operation count.
    • If on initial phase no continent is found then it creates a new one.
      • Data is stored as {entityId:"",name:'Asia',links_gen:2,links_redirect:1,visitor:12}
class Continent extends Entity { }
const continentSchema = new Schema(Continent, {
    name: { type: 'string', indexed: true },
    links_gen: { type: 'number' },
    links_redirect: { type: 'number' },
    visitor: { type: 'number' },
});
let continentEntity = ContinentRepository().search().where('name').equals(result.continent).return.all();
if (continentEntity.length) {
    continentEntity[0].entityData[[type]] += 1;
    ContinentRepository().save(continentEntity[0]);
} else {
    const entity = ContinentRepository().createEntity();
    entity.name = result.continent;
    entity.visitor = 1;
    entity.links_gen = 0;
    entity.links_redirect = 0;
    ContinentRepository().save(entity);
}

How the data is accessed:

  • Urls.
    • Code is base62 counter value.
    • On success it redirect to the original url and on failure 404 page.
url=UrlRepository().search().where('short_url').equals(code).return.first();
In place of all we can use first also
  • Expression.
    • A list is fetched, which has count of visitor, link generated, links redirected, thumbs up, like and heart except the counter range.
const records = CounterRepository().search().return.all();
  • Continent.
    • For desktop view individual continents analytics are fetched by continent name and for mobile view a list of continents are fetched.
records = await ContinentRepository().search().where('name').equals(c).return.all();
records = await ContinentRepository().search().return.all();

How to run it locally?

Prerequisites

  • NodeJs 14.x
  • Npm 6.x

Local installation

  • Backend setup guide
    • git clone https://github.com/anshulnegitc/url-shortener-app-backend.git
    • cd project-directory
    • npm install
    • create .env file and save variable as follows
    • set NODE_ENV to 'local' when running locally otherwise production.
NODE_ENV=local
REDIS_URL = "Paste Redis host url here in this format [redis://username:password@connection-url:port]"   
PORT = 51029
LINK_EXPIRATION_TIME = 1800
FRONT_END_URL = http://localhost:3000/
LOCAL_IP="" 
[ paste your ip address here as in local env. 
no analytics will be recorded so setting it manually 
follow this link https://www.whatismyip.com/]
  • and at last run command node index.js

  • Frontend setup guide

    • git clone https://github.com/anshulnegitc/url-shortener-app-frontend.git
    • cd project-directory
    • npm install
    • create .env file and save variable as follows
REACT_APP_BASE_URL=http://localhost:51029/
  • and at last run command npm start

Deployment

Deploy

Set environment variables
FRONT_END_URL = "" //Frontend url eg https://u-sh-app.herokuapp.com/
LINK_EXPIRATION_TIME = 1800 //expiration time in seconds
NODE_ENV = production
REDIS_URL="" // redis host url

More Information about Redis Stack

Here some resources to help you quickly get started using Redis Stack. If you still have questions, feel free to ask them in the Redis Discord or on Twitter.

Getting Started

  1. Sign up for a free Redis Cloud account using this link and use the Redis Stack database in the cloud.
  2. Based on the language/framework you want to use, you will find the following client libraries:

The above videos and guides should be enough to get you started in your desired language/framework. From there you can expand and develop your app. Use the resources below to help guide you further:

  1. Developer Hub - The main developer page for Redis, where you can find information on building using Redis with sample projects, guides, and tutorials.
  2. Redis Stack getting started page - Lists all the Redis Stack features. From there you can find relevant docs and tutorials for all the capabilities of Redis Stack.
  3. Redis Rediscover - Provides use-cases for Redis as well as real-world examples and educational material
  4. RedisInsight - Desktop GUI tool - Use this to connect to Redis to visually see the data. It also has a CLI inside it that lets you send Redis CLI commands. It also has a profiler so you can see commands that are run on your Redis instance in real-time
  5. Youtube Videos