Making Flutter and REST API Work Together — Sending POST Request (Part 4)

Alex Josef Bigler
Full Struggle Developer
4 min readMar 23, 2023

Support for sending POST requests is critical for mobile applications because it allows for sending data to a server for processing, creating, updating, or deleting records in a database, and many other operations that are essential for most modern applications.

The following posts are suggested reading for this post to get you started:

Now that we understand how to send a GET request and work with the response, how do we send JSON in the body of a POST request?

All we need to do is serialize the object into JSON.

From words to action

Note: This material is created to demonstrate the deserialization process itself, rather than the process of sending a POST request, so this part will be indirectly touched upon. However, in the article, we will deserialize all commonly used objects.

To practice sending POST requests and not break anyone’s real server, we will use the service JSONPlaceholder.

If you want to deploy such a server yourself, you can read my article here 👈.

In the api_data_provider.dart file, we add the ForecastContract class. We will deserialize a string, an object, an array of objects, and an array of numbers. Next, line by line:

  • Line 9 — This is the opposite of the fromJson method. There, we had a Map<String, dynamic> input, and here, our task is to obtain such an array as output.
  • Line 12— We declare a class for nested object, which we will also deserialize, and we also add the toJson method to it.

In our ApiDataProvider class, we will add a POST method and go through it line by line:

The differences from the GET method are minimal.

  • Line 7— deserialization.
  • Line 8— we change the method from GET to POST.

Now, to control the success of the request, we check for a status code of 201 instead of 200, which means a successful creation of a new resource on the server.

Also, in addition to the id field indicating the identifier of the new entity, the response should return the body of our request.

To handle it, we write several classes:

class ForecastContractResponse {
final String title;
final List<int> nums;
final ForecastContractResponseItem item;
final List<ForecastContractResponseItem> items;
final int id;

ForecastContractResponse(this.title, this.nums, this.item, this.items, this.id);

factory ForecastContractResponse.fromJson(Map<String, dynamic> json) => ForecastContractResponse(
json["title"],
List<int>.from(json["nums"].map((x) => x)),
ForecastContractResponseItem.fromJson(json["item"]),
List<ForecastContractResponseItem>.from(json["items"].map((x) => ForecastContractResponseItem.fromJson(x))),
json["id"],
);

Map<String, dynamic> toJson() => {
"title": title,
"nums": List<dynamic>.from(nums.map((x) => x)),
"item": item.toJson(),
"items": List<dynamic>.from(items.map((x) => x.toJson())),
"id": id,
};
}

class ForecastContractResponseItem {
ForecastContractResponseItem({
required this.title,
});

final String title;

factory ForecastContractResponseItem.fromJson(Map<String, dynamic> json) => ForecastContractResponseItem(
title: json["title"],
);

Map<String, dynamic> toJson() => {
"title": title,
};
}

You may notice that items are collected into arrays using the map() iterator. Yes, this method is slower than what we did before (and I complained a bit about it in the first article), but it’s just my professional deformation, and who cares about that anyway.

We will add a new test in the api_data_provider_test.dart file to verify the results of the POST request. The JSONPlaceholder service should return not only the 201 status code but also the body of our request and the id field. Therefore, we will check for the presence of the id field, which indicates that our request was processed and some new resource was created on the server:

  test('POST contract was encoded', () async {
final provider = ApiDataProvider();
var result = await provider.postWeather(ForecastContract('test', ForecastContractItem('test'), [ForecastContractItem('111')], [1, 2]));
expect(result.id, closeTo(100, 500));
});

At the breakpoint in the postWeather method, we can see our deserialized object:

If we remove the backslashes and format the string (for example using https://jsoneditoronline.org), we get the following JSON:

{
"title": "test",
"nums": [
1,
2
],
"item": {
"title": "test"
},
"items": [
{
"title": "111"
}
]
}

Important: We remove the slashes because they indicate that a special character follows. In JSON, quotes are essential, but in Dart, quotes indicate the beginning and end of a string. Without the slash, the JSON would break at the first quote.

Instead of the Conclusion

The test, by the way, also completed without errors:

And that means we can go have a coffee and think about important questions like how to make something more beautiful, simple, and easy to maintain in the future from this code that was written in 5 minutes. By the way, this is exactly what the next article will be about.

Subscribe and don’t miss new materials!

--

--

Alex Josef Bigler
Full Struggle Developer

Enthusiast of new technologies, entrepreneur, and researcher. Writing about IT, economics, and other stuff. Exploring the world through the lens of data.