ProductPromotion
Logo

0x3d.Site

is designed for aggregating information.

Connecting Flutter to the Node.js Backend – Making the Magic Happen

You’ve built a beautiful Flutter frontend. You’ve crafted a solid Node.js backend. Now it’s time to connect the dots and make your app fully functional. In this tutorial, we’ll focus on how to make HTTP requests from your Flutter app to your Node.js backend, handle the responses, and gracefully deal with errors. We’ll also dive into building a simple login and signup system, giving your app some much-needed user authentication features.

Making HTTP Requests from Flutter to Node.js

Imagine your Flutter app as someone sending texts, and your backend is the friend on the other end. Whenever your app needs something—like fetching data or sending info—it sends an HTTP request to the backend. The backend processes that request and sends a response back, just like your friend replying to your text. But instead of emojis and memes, the data usually comes in JSON format.

We’re going to use the http package in Flutter to handle these requests. Let’s jump in and see how to set it up!

Step 1: Install the http Package

To make HTTP requests in Flutter, we need the http package. Open your pubspec.yaml file and add this line under the dependencies section:

dependencies:
  flutter:
    sdk: flutter
  http: ^0.13.3

Then, run this command in your terminal to install the package:

flutter pub get

Step 2: Making a GET Request

Let’s start with something simple—getting data from the backend. We’ll create a method that fetches a list of users from the Node.js backend.

  1. Open your main.dart file and import the http package:

    import 'package:http/http.dart' as http;
    import 'dart:convert';
    
  2. Create a function that fetches users from the backend:

    Future<List<dynamic>> fetchUsers() async {
      final response = await http.get(Uri.parse('http://localhost:3000/users'));
    
      if (response.statusCode == 200) {
        return json.decode(response.body);
      } else {
        throw Exception('Failed to load users');
      }
    }
    

    What’s happening here?

    • http.get: This sends a GET request to the /users route we created in the backend.
    • response.statusCode: We check if the response status is 200, which means everything went fine.
    • json.decode(response.body): If the response is good, we decode the JSON data and return it as a list.
    • If something goes wrong, we throw an error.
  3. Now, let’s display the fetched users in your Flutter app’s UI:

    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      late Future<List<dynamic>> users;
    
      @override
      void initState() {
        super.initState();
        users = fetchUsers();
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text('User List'),
            ),
            body: FutureBuilder<List<dynamic>>(
              future: users,
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  return ListView.builder(
                    itemCount: snapshot.data?.length,
                    itemBuilder: (context, index) {
                      return ListTile(
                        title: Text(snapshot.data?[index]['name']),
                      );
                    },
                  );
                } else if (snapshot.hasError) {
                  return Center(child: Text("Error: ${snapshot.error}"));
                }
    
                return Center(child: CircularProgressIndicator());
              },
            ),
          ),
        );
      }
    }
    
    void main() => runApp(MyApp());
    

In this code, we use FutureBuilder to handle the async nature of our fetchUsers() function. If the data is available, it displays a list of user names. If there’s an error, it shows the error message. Otherwise, a loading spinner is displayed while waiting for the response.

Step 3: Making a POST Request

Now, let’s make a POST request to add a new user. We’ll create a simple form in Flutter, where users can enter a name, and this name will be sent to the backend to create a new user.

  1. Create a method to send the POST request:

    Future<void> addUser(String name) async {
      final response = await http.post(
        Uri.parse('http://localhost:3000/users'),
        headers: <String, String>{
          'Content-Type': 'application/json; charset=UTF-8',
        },
        body: jsonEncode(<String, String>{
          'name': name,
        }),
      );
    
      if (response.statusCode == 201) {
        print('User added successfully');
      } else {
        throw Exception('Failed to add user');
      }
    }
    
  2. Add a simple form to your app’s UI:

    class AddUserForm extends StatefulWidget {
      @override
      _AddUserFormState createState() => _AddUserFormState();
    }
    
    class _AddUserFormState extends State<AddUserForm> {
      final TextEditingController _controller = TextEditingController();
    
      @override
      Widget build(BuildContext context) {
        return Column(
          children: <Widget>[
            TextField(
              controller: _controller,
              decoration: InputDecoration(labelText: 'Enter user name'),
            ),
            ElevatedButton(
              onPressed: () {
                addUser(_controller.text);
              },
              child: Text('Add User'),
            ),
          ],
        );
      }
    }
    

    Now, when you enter a name and press the "Add User" button, it sends a POST request to the Node.js backend, adding the new user to the database.

Handling Responses: JSON and All That Good Stuff

Handling responses is a big part of connecting the frontend with the backend. Every time your Flutter app makes a request to the Node.js server, it gets a response in JSON format.

What Is JSON?

JSON stands for JavaScript Object Notation, and it’s a lightweight data format that’s easy for both humans and machines to read. Think of it as a neatly structured package that your backend sends to your frontend. It’s like getting your mail organized in neat little envelopes, instead of everything just thrown into your mailbox.

Here’s a quick example of JSON data:

{
  "id": 1,
  "name": "Alice"
}

In Flutter, when you receive this data, you can decode it using the json.decode() function, as we saw earlier in the fetchUsers() function. Once you’ve decoded the JSON, you can easily access the data using dot notation or by indexing into the list or map.

Error Handling: Because Things Will Go Wrong

If everything worked perfectly all the time, we wouldn’t need error handling. But in reality, things break—sometimes the server is down, sometimes the network is shaky, and sometimes you just forget to turn something on. Your app needs to know what to do when things go wrong, or else it’ll crash, and no one wants that.

Step 1: Handling Common Errors

When making HTTP requests in Flutter, errors can happen for many reasons:

  • Network issues: If the user has a bad internet connection, requests might fail.
  • Server issues: If your Node.js server is down, your app won’t get the data it needs.
  • Invalid data: Sometimes, the backend might send unexpected data.

In your code, you can handle these errors using try and catch blocks. For example:

Future<List<dynamic>> fetchUsers() async {
  try {
    final response = await http.get(Uri.parse('http://localhost:3000/users'));

    if (response.statusCode == 200) {
      return json.decode(response.body);
    } else {
      throw Exception('Failed to load users');
    }
  } catch (error) {
    print('Error: $error');
    throw error;
  }
}

If the request fails for any reason, the error is caught, and you can handle it gracefully—whether that means showing an error message to the user, retrying the request, or something else.

Step 2: Displaying Errors in the UI

You can also display errors in the UI using Flutter’s FutureBuilder. In the example earlier, we showed an error message when the request failed:

else if (snapshot.hasError) {
  return Center(child: Text("Error: ${snapshot.error}"));
}

This way, the user knows something went wrong instead of staring at a blank screen.

Real-World Example: User Authentication

Let’s build a simple login and signup system to demonstrate how Flutter can send user data (like a username and password) to your Node.js backend. Authentication is a common feature in apps, and this will give your app some real-world functionality.

Step 1: Setting Up Routes in Node.js

First, we’ll create two routes in the backend: one for signup and one for login. Add this code to your server.js file:

// Signup route
app.post('/signup', (req, res) => {
  const { username, password } = req.body;

  // Here you would normally

 hash the password and store it in the database
  // For simplicity, we'll just store the username and password as is
  users.push({ username, password });
  res.status(201).json({ message: 'User signed up successfully' });
});

// Login route
app.post('/login', (req, res) => {
  const { username, password } = req.body;

  // Check if the user exists and the password matches
  const user = users.find(u => u.username === username && u.password === password);

  if (user) {
    res.json({ message: 'Login successful' });
  } else {
    res.status(401).json({ message: 'Invalid credentials' });
  }
});

This is a simple authentication system. In a real app, you would hash passwords and store them securely in a database, but for this example, we’re keeping it basic.

Step 2: Creating the Login and Signup Forms in Flutter

Now, let’s add the login and signup forms to your Flutter app:

class LoginForm extends StatefulWidget {
  @override
  _LoginFormState createState() => _LoginFormState();
}

class _LoginFormState extends State<LoginForm> {
  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  Future<void> login() async {
    final response = await http.post(
      Uri.parse('http://localhost:3000/login'),
      headers: <String, String>{
        'Content-Type': 'application/json; charset=UTF-8',
      },
      body: jsonEncode(<String, String>{
        'username': _usernameController.text,
        'password': _passwordController.text,
      }),
    );

    if (response.statusCode == 200) {
      print('Login successful');
    } else {
      print('Login failed');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        TextField(
          controller: _usernameController,
          decoration: InputDecoration(labelText: 'Username'),
        ),
        TextField(
          controller: _passwordController,
          decoration: InputDecoration(labelText: 'Password'),
          obscureText: true,
        ),
        ElevatedButton(
          onPressed: login,
          child: Text('Login'),
        ),
      ],
    );
  }
}

When the user submits the form, it sends a POST request to the /login route in the backend, which checks the credentials and returns a success or failure message.

Congratulations! In this tutorial, you’ve connected your Flutter frontend with your Node.js backend. You’ve learned how to send data between the two using HTTP requests, handle JSON responses, and deal with errors. You even built a simple user authentication system with login and signup features.

Flutter and Node.js: Build Full-Stack Cross-Platform Apps

In this course, you'll learn to build full-stack cross-platform applications using Flutter and Node.js. Start by setting up your development environment, create stunning UIs with Flutter, and develop a Node.js backend to handle data. You’ll also discover how to deploy your app, maintain its performance, and engage with users, giving you the skills to tackle real-world challenges in web and mobile development.

Questions & Answers

to widen your perspective.

Tools

available to use.

Providers

to have an visit.

Resouces

to browse on more.
0x3d
https://www.0x3d.site/
0x3d is designed for aggregating information.
NodeJS
https://nodejs.0x3d.site/
NodeJS Online Directory
Cross Platform
https://cross-platform.0x3d.site/
Cross Platform Online Directory
Open Source
https://open-source.0x3d.site/
Open Source Online Directory
Analytics
https://analytics.0x3d.site/
Analytics Online Directory
JavaScript
https://javascript.0x3d.site/
JavaScript Online Directory
GoLang
https://golang.0x3d.site/
GoLang Online Directory
Python
https://python.0x3d.site/
Python Online Directory
Swift
https://swift.0x3d.site/
Swift Online Directory
Rust
https://rust.0x3d.site/
Rust Online Directory
Scala
https://scala.0x3d.site/
Scala Online Directory
Ruby
https://ruby.0x3d.site/
Ruby Online Directory
Clojure
https://clojure.0x3d.site/
Clojure Online Directory
Elixir
https://elixir.0x3d.site/
Elixir Online Directory
Elm
https://elm.0x3d.site/
Elm Online Directory
Lua
https://lua.0x3d.site/
Lua Online Directory
C Programming
https://c-programming.0x3d.site/
C Programming Online Directory
C++ Programming
https://cpp-programming.0x3d.site/
C++ Programming Online Directory
R Programming
https://r-programming.0x3d.site/
R Programming Online Directory
Perl
https://perl.0x3d.site/
Perl Online Directory
Java
https://java.0x3d.site/
Java Online Directory
Kotlin
https://kotlin.0x3d.site/
Kotlin Online Directory
PHP
https://php.0x3d.site/
PHP Online Directory
React JS
https://react.0x3d.site/
React JS Online Directory
Angular
https://angular.0x3d.site/
Angular JS Online Directory