flutter-http-peticiones-get-post

HTTP Requests in Flutter with GET and POST

  • 4 min

An HTTP request is a message that an app sends to a server to request or send data.

In the previous article, we organized our code by creating a Service. Now we are going to fill that service with real logic.

For our Flutter application to talk to a server (a REST API), we need an HTTP client. Although Dart comes with native tools like HttpClient, it is often more comfortable to start with the http package.

It is lightweight, based on Future (asynchronous), and very easy to use. Let’s see how to perform the operations you will use in 90% of your Apps.

Installing the http package

As we saw in the first modules, external libraries are managed in pubspec.yaml.

Open a terminal in the root of your project and run:

flutter pub add http
Copied!

This will add the latest compatible version to your configuration file. Now, in your service file (user_service.dart), import it like this:

import 'dart:convert'; // To transform data to JSON
import 'package:http/http.dart' as http;
Copied!

Why as http? It’s a good practice to give it an alias. This way, when we write code, we will use http.get(...) instead of get(...). This avoids confusion with other functions in your code that might have the same name.

GET Request to Read Data

The GET verb is used to request information from the server. This is what your browser does when you enter a website.

For this example, we will use JSONPlaceholder, a free, fake public API for testing.

Future<void> obtenerUsuarios() async {
  // 1. Define the URL (Endpoint)
  // The http package receives a Uri object
  var url = Uri.parse('https://jsonplaceholder.typicode.com/users');

  // 2. Make the call (Wait with await)
  var response = await http.get(url);

  // 3. Check if it was successful
  if (response.statusCode == 200) {
    // 200 OK: The request was successful
    print('Server response: ${response.body}');
  } else {
    // 404, 500, etc: Something went wrong
    print('Error in request: ${response.statusCode}');
  }
}
Copied!

The Uri object

Notice Uri.parse(...). The http package API receives a Uri object, which separately represents the scheme, domain, path, and parameters. Uri.parse checks the syntax, but it also accepts relative URIs, so it does not guarantee by itself that a domain exists or that the server will respond.

POST Request to Send Data

The POST verb is used to send new information to the server (create a user, post a comment, log in).

Here things change a bit because we need to send two extra things:

  1. Headers: To tell the server “Hey, I’m sending you data in JSON format.”
  2. Body: The data itself, converted to a String.
Future<void> crearUsuario() async {
  var url = Uri.parse('https://jsonplaceholder.typicode.com/users');

  // Make the POST
  var response = await http.post(
    url,
    // 1. Headers: Important to specify the content type
    headers: {
      "Content-Type": "application/json; charset=UTF-8",
    },
    // 2. Body: Convert our Dart map to a JSON String
    body: jsonEncode({
      "name": "Luis Llamas",
      "username": "luisllamas",
      "email": "[email protected]"
    }),
  );

  if (response.statusCode == 201) {
    // 201 Created: The resource was created successfully
    print('User created successfully: ${response.body}');
  } else {
    print('Error creating user: ${response.statusCode}');
  }
}
Copied!

To use jsonEncode, you need to import dart:convert. This function transforms a Dart map into a valid JSON text string, for example {"key":"value"}, which is what travels over the network.

Integrating It into the Service

Now let’s go back to our user_service.dart from the previous article and make it actually work.

import 'dart:convert';
import 'package:http/http.dart' as http;

class UserService {
  final String _baseUrl = 'jsonplaceholder.typicode.com';

  Future<List<dynamic>> getUsers() async {
    // Build the URL safely
    final url = Uri.https(_baseUrl, '/users');

    final response = await http.get(url);

    if (response.statusCode == 200) {
      // ✅ SUCCESS
      // response.body is a huge STRING.
      // jsonDecode converts it to a List of Maps (List<dynamic>)
      String body = response.body;
      List<dynamic> decodedData = jsonDecode(body);
      
      return decodedData;
    } else {
      // ❌ ERROR
      throw Exception('Failed to load users');
    }
  }
}
Copied!

The Problem with the dynamic Type

If you look at the code above, I returned List<dynamic>.

This means that when you use this data on your screen, you will have to do things like: user['name'] or user['email'].

Text(users[index]['nmae']) // 😱 Typo ('nmae'), and Dart won't warn you
Copied!

Working with dynamic is dangerous. You lose autocompletion, and if you misspell a property name, the App will crash in the user’s face.