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.
- Registration.
- Login.
- 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
In above flutter project I have 4 dart files namely:
- main.dart
- registration.dart
- login.dart
- 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"), ),), ], ), ), ), ), ); } }
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"), ), ], ), ), ), ), ); } }
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']}'), ), ); } ), ), ) ], ), ), ), ), ), ); } }
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.