Flutter url shortener project

Hi Guy’s Welcome to Proto Coders Point. It this fast growing digital era the importance of concise and shareable URL’s cannot be overstated. If you are trying to make you web address URL manageable or want to share the link of any content on social media or want to embed the URL in a email, but share a URL that is too long is very annoying thing. There for Shortened URL Plays a crucial role.
So In this article we learn how to build a URL Shortener Application in flutter.

How to user flutter URL Shortener

Our Flutter URL Shortener Application we have 3 pages.

  1. Registration.
  2. Login.
  3. Dashboard.

In Registration Page we simply have a form that the user can fill to register himself into our application using Flutter registration page.

In Login page user can enter his login credential and get logged in into the flutter to make use of URL Shortener.

In Dashboard we have 2 section. First section user can use to submit his LongURL and get ShortURL. Second section we can show all the data i.e. short URL created by that user.


Libraries need to created URL Shorten project in flutter

In pubspec.yaml file under dependencies we need to add below 2 library.

  get:
  get_storage:

We are going to make use of getx and get storage package

getx: used to make http calls to back api to store and retrieve data from backend nodejs server.

get storage: used to share logged in user data within the application storage same like sharedPreference.

Flutter URL Shortener Project Structure

url shortener flutter

In above flutter project I have 4 dart files namely:

  1. main.dart
  2. registration.dart
  3. login.dart
  4. dashboard.dart

main.dart

This is the starting point of our flutter application, Here we will check if the user has already signed into the application before, If the user data exist in get_storage (shared preferences) we will redirect the user to dashboard page else will redirect user to login page.

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:url_shortener/dashboard.dart';
import 'package:url_shortener/login.dart';
import 'package:get_storage/get_storage.dart';
void main() async{
  await GetStorage.init();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  final get_storage = GetStorage();
  @override
  void initState() {
    // TODO: implement initState
    super.initState();

    get_storage.writeIfNull('user', false);

    Future.delayed(Duration(seconds: 2),() async{

      print(get_storage.read('user'));
       checkUserData();
    });


  }

  checkUserData(){
    if(get_storage.read('user').toString().isNotEmpty || get_storage.read('user') ){
      Navigator.push(context, MaterialPageRoute(builder: (builder)=>Dashboard()));
    }else{
      Navigator.push(context, MaterialPageRoute(builder: (builder)=>Login()));
    }
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: CircularProgressIndicator(),
      ),
    );
  }
}

login.dart

In login page we have 2 text field where the user can enter login credential i.e. email & password and a button on click will call a function that hit back-end NodeJS Login API.

After hitting the backEnd API if user exist in our MongoDB database will send the user data as response to frontEnd, and then store the user data into flutter app storage space using GetStorage package so that the used will be signIn into the application when he visit next time.

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:url_shortener/dashboard.dart';
import 'package:url_shortener/registration.dart';
import 'package:get_storage/get_storage.dart';

class Login extends StatefulWidget {
  const Login({super.key});

  @override
  State<Login> createState() => _LoginState();
}

class _LoginState extends State<Login> {

  TextEditingController emailText = TextEditingController();
  TextEditingController passText = TextEditingController();
  final getConnect = GetConnect();
  final get_storage = GetStorage();

  void _login(email,pass) async{

    if(email.isEmpty || pass.isEmpty){
      Get.snackbar("Please Enter Email And Password", '');
    }else{
      final res = await getConnect.post('http://192.168.29.239:3000/userLogin', {
        "email":email,
        "password":pass

      });

      if(res.body['status']){
        get_storage.write('user', res.body['success']);
        Navigator.push(context, MaterialPageRoute(builder: (builder)=>Dashboard()));
      }else{
        Get.snackbar(res.body['success'], '');
      }
    }

  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: SingleChildScrollView(
          child: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                SizedBox(height: 10,),
                const Text("* URL SHORTENER *",style: TextStyle(fontSize: 30),),
                const Text("Login Page"),
                SizedBox(height: 10,),
                Padding(
                  padding: const EdgeInsets.fromLTRB(25, 20, 25, 2),
                  child: TextField(
                    controller: emailText,
                    keyboardType: TextInputType.text,
                    decoration: InputDecoration(
                        filled: true,
                        fillColor: Colors.white,
                        hintText: "Email",
                        border: OutlineInputBorder(
                            borderRadius: BorderRadius.all(Radius.circular(10.0)))),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.fromLTRB(25, 20, 25, 2),
                  child: TextField(
                    controller: passText,
                    keyboardType: TextInputType.text,
                    decoration: InputDecoration(
                        filled: true,
                        fillColor: Colors.white,
                        hintText: "Password",
                        border: OutlineInputBorder(
                            borderRadius: BorderRadius.all(Radius.circular(10.0)))),
                  ),
                ),

                ElevatedButton(
                  onPressed: () {
                      _login(emailText.text,passText.text);
                  },
                  child: Text("LOGIN"),
                ),

                Padding(padding: EdgeInsets.all(20),child:
                ElevatedButton(
                  onPressed: () {
                    Navigator.push(context, MaterialPageRoute(builder: (builder)=>Registration()));
                  },
                  child: Text("REGISTER"),
                ),),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
url shortener login page

registration.dart

Using this page user can register himself into the system.

Here we accept 3 data from the user i.e. Name, Email and Password using Text Fields.

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:url_shortener/login.dart';


class Registration extends StatefulWidget {
  const Registration({super.key});

  @override
  State<Registration> createState() => _RegistrationState();
}

class _RegistrationState extends State<Registration> {

  TextEditingController nameText = TextEditingController();
  TextEditingController emailText = TextEditingController();
  TextEditingController passText = TextEditingController();
  final getConnect = GetConnect();


  void _register(name,email,pass) async{
    print("${name},${email},${pass}");

    if(name.isEmpty || email.isEmpty || pass.isEmpty){
      Get.snackbar("Please Enter Details", '');
    }else{
      final res = await getConnect.post('http://192.168.29.239:3000/userRegistration', {
        "name":name,
        "email":email,
        "password":pass
      });

      if(res.body['status']){
        Navigator.push(context, MaterialPageRoute(builder: (builder)=>Login()));
      }else{
        Get.snackbar(res.body['success'], 'message');
      }
    }

  }
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: SingleChildScrollView(
          child: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                SizedBox(height: 10,),
                const Text("* URL SHORTENER *",style: TextStyle(fontSize: 30),),
                const Text("Registration Page"),
                SizedBox(height: 10,),
                Padding(
                  padding: const EdgeInsets.fromLTRB(25, 10, 25, 2),
                  child: TextField(
                    controller: nameText,
                    keyboardType: TextInputType.text,
                    decoration: InputDecoration(
                        filled: true,
                        fillColor: Colors.white,
                        hintText: "Full Name",
                        border: OutlineInputBorder(
                            borderRadius: BorderRadius.all(Radius.circular(10.0)))),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.fromLTRB(25, 20, 25, 2),
                  child: TextField(
                    controller: emailText,
                    keyboardType: TextInputType.text,
                    decoration: InputDecoration(
                        filled: true,
                        fillColor: Colors.white,
                        hintText: "Email",
                        border: OutlineInputBorder(
                            borderRadius: BorderRadius.all(Radius.circular(10.0)))),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.fromLTRB(25, 20, 25, 2),
                  child: TextField(
                    controller: passText,
                    keyboardType: TextInputType.text,
                    decoration: InputDecoration(
                        filled: true,
                        fillColor: Colors.white,
                        hintText: "Password",
                        border: OutlineInputBorder(
                            borderRadius: BorderRadius.all(Radius.circular(10.0)))),
                  ),
                ),
                Padding(padding: EdgeInsets.all(20),child:
                ElevatedButton(
                  onPressed: () {
                      _register(nameText.text,emailText.text,passText.text);
                  },
                  child: Text("REGISTER"),
                ),),
                ElevatedButton(
                  onPressed: () {
                    Navigator.push(context, MaterialPageRoute(builder: (builder)=>Login()));
                  },
                  child: Text("LOGIN"),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
url shortener registration page

dashboard.dart

This Page and 2 section

  • First section user can use to submit his LongURL and get ShortURL.
  • Second section we can show all the data i.e. short URL created by that user.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';

class Dashboard extends StatefulWidget {
  const Dashboard({super.key});

  @override
  State<Dashboard> createState() => _DashboardState();
}

class _DashboardState extends State<Dashboard> {
  final getStoage = GetStorage();
  final textLongUrl = TextEditingController();
  final getConnect = GetConnect();

  List<Map<String,dynamic>> dataList = [];

  void _urlSubmit(longurl) async{

    Map<String,dynamic> userData = getStoage.read('user');
    String userId = userData['_id'];

    final res = await getConnect.post('http://192.168.29.239:3000/urlSubmit',
        {
          'userId': userId,
          'longUrl': longurl
    });

    print(res.body['shortUrl']);

    Get.snackbar("Short URL Created", res.body['shortUrl']);
    textLongUrl.text="";
  }

  Future<void> _fetchUserUrl(userId) async {
  
    final response = await getConnect.post('http://192.168.29.239:3000/getUserURL', {
        'userId' : userId
    });

    final List<dynamic> data = response.body['success'];

    setState(() {
      dataList = List<Map<String,dynamic>>.from(data);
    });
    
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    Map<String,dynamic> userData = getStoage.read('user');
    String userId = userData['_id'];

    _fetchUserUrl(userId);

  }

  @override
  Widget build(BuildContext context) {
    return  Scaffold(
      body: SafeArea(
        child: SingleChildScrollView(
          child: Center(
            child: Container(
              height: MediaQuery.of(context).size.height,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  SizedBox(height: 10,),
                  const Text("* URL SHORTENER *",style: TextStyle(fontSize: 30),),
                  const Text("Long URL to Short URL"),
                  SizedBox(height: 10,),
                  Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Form(
                      child: Row(
                        children: [
                          Expanded(
                            child: TextFormField(
                                decoration: InputDecoration(
                                  filled: true,
                                  fillColor: Colors.white,
                                  hintText: "Long URL",
                                  border: OutlineInputBorder(
                                      borderRadius: BorderRadius.all(Radius.circular(10.0))
                                  ),
                                ),
                                controller: textLongUrl,
                                validator: (value){
                                  if(value == null || value.isEmpty){
                                    return " Please Enter long Url";
                                  }
                                  return null;
                                }
                            ),
                          ),
                          SizedBox(width: 10), // Add some spacing between TextField and Button
                          ElevatedButton(
                            onPressed: () {
                              _urlSubmit(textLongUrl.text);
                            },
                            child: Text('Submit'),
                          ),
                        ],
                      ),
                    ),
                  ),
                  dataList.isEmpty ? CircularProgressIndicator(): Expanded(
                    child: Container(
                      child: ListView.builder(
                        itemCount: dataList.length,
                          itemBuilder: (context,index){
                          return Card(
                            elevation: 2,
                            margin: EdgeInsets.symmetric(vertical: 6,horizontal: 16),
                            child: ListTile(
                              title: Text("http://192.168.29.239/${dataList[index]['shorturl']}"),
                              subtitle: Text('${dataList[index]['longUrl']}'),
                            ),
                          );
                          }
                      ),
                    ),
                  )
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}
url shortener dashboard page

Video Tutorial on building URL Shortener Project

Below is playlist of my YouTube tutorial on building URL Shortener Application using Flutter for frontend and NodeJS with MongoDB at backend.


URL Shortener BackEnd complete source code