Flutter HTTP Calls

Scaibu
5 min readJul 2, 2023

--

  • The Importance of Protocols for APIs

As you know, application programming interfaces serve as bridges between at least two apps. They can facilitate communication over the web, in which case they’re called web services, and follow web protocols (most likely HTTP). Alternatively, they can connect two internal pieces of software on a private network, in which case the developers can create whatever protocols they want.

As long as one program’s function is called and a request goes to retrieve data from a different program, this interaction is an API. The important part is that the communication happens successfully. So, the API’s role is to ensure that both the request and response between apps are understood. That’s why protocols are a must.

Another important factor besides the protocol is the format.

Think back to the “name, surname” example I presented. What if the computer asked me to type out my identity and instead I sent an audio file of me saying my name and surname? Even if the order is correct, the format isn’t. The computer didn’t expect an audio file, and it doesn’t know how to interpret it.

HTTP — The crucial web protocol

Hyper-Text Transfer Protocol, or HTTP, is the primary protocol for any web-based communication. Since it’s so widely spread and plenty of APIs are built to operate over the Internet, it’s no wonder that plenty of APIs have adopted HTTP as their standard protocol. choosing HTTP as the protocol for the API gives you a few key advantages:

  • Most developers are familiar with the protocol, so it’s easy to use, update and scale.
  • The apps require little processing, so it’s faster than other protocols.
  • Its flexibility means that APIs built on it can accomplish a wide variety of objectives.
  • Responses can be cached, meaning that repeated commands are processed faster.

HTTP request structure :

Requests consist of the following elements:

  • An HTTP method, usually a verb like GET, POST, or a noun like OPTIONS or HEAD that defines the operation the client wants to perform. Typically, a client wants to fetch a resource (using GET) or post the value of an HTML form (using POST), though more operations may be needed in other cases.
  • The path of the resource to fetch; the URL of the resource stripped from elements that are obvious from the context, for example without the protocol (http://), the domain , or the TCP port (here, 80).
  • The version of the HTTP protocol.
  • Optional headers that convey additional information for the servers.
  • A body, for some methods, similar to those in responses, which contains the resource sent.

HTTP request structure :

Responses consist of the following elements:

  • The version of the HTTP protocol they follow.
  • A status code, indicating if the request was successful or not, and why.
  • A status message, a non-authoritative short description of the status code.
  • HTTP headers, like those for requests.
  • Optionally, a body containing the fetched resource.

Right folder structure for API Request

Making and handling HTTP calls

  • Creating a header for a large project
static Map<String, String> createHeader() {
Map<String, String> header = {
HttpHeaders.contentTypeHeader: 'application/json',
};

/// YOU CAN ADD ANY CONDITION HERE FOR ADDING HEADER
/// FOR A PARTICULAR CONDTION LIKE FOR PAYMENT GATE-WAY CALL
if (Auth.isSignIn) {
header.putIfAbsent(
HttpHeaders.authorizationHeader,
() => 'Bearer ${Auth.apiToken}',
);
}

return header;
}

Creating base URL

/// IN APP IS MORE THAN 2 BASE URL THE YOU CAN MAKE CHANGES HERE
static Uri createURL({required String endPoint}) {
if (!endPoint.startsWith('http')) {
return Uri.parse('$BASE_URL$endPoint');
} else {
return Uri.parse('$BASE_URL$endPoint');
}
}

Creating request :

static Future request({
HttpRequestMethod type = HttpRequestMethod.GET,
required String endPoint,
required Map<String, dynamic> requestBody,
Map<String, dynamic>? headers,
String uploadKey = '',
String uploadFilePath = '',
required String requestAPIName,
void Function(int)? onStatusCodeError,
}) async {
if (await isNetworkAvailable()) {
Response response = Response('', 200);
StreamedResponse streamedResponse = StreamedResponse(Future(() => <int>[]).asStream(), 200);

Uri url = createURL(endPoint: endPoint);

Map<String, String> headers = createHeader();

/// SORTING REQUEST TYPE

try {
switch (type) {
case HttpRequestMethod.GET:
response = await get(url, headers: headers);
break;

case HttpRequestMethod.POST:
response = await post(url, body: json.encode(requestBody), headers: headers);
break;

case HttpRequestMethod.DELETE:
response = await delete(url, body: json.encode(requestBody), headers: headers);
break;

case HttpRequestMethod.PUT:
response = await put(url, body: json.encode(requestBody), headers: headers);
break;

case HttpRequestMethod.PATCH:
response = await patch(url, body: json.encode(requestBody), headers: headers);
break;

case HttpRequestMethod.UPLOAD:
MultipartRequest request = MultipartRequest('POST', url);
request.files.add(await MultipartFile.fromPath(uploadKey, uploadFilePath));
request.headers.addAll(headers);
streamedResponse = await request.send();
break;

case HttpRequestMethod.DOWNLOAD:
log('please handle download request');
return '';
}

if (type == HttpRequestMethod.UPLOAD || type == HttpRequestMethod.DOWNLOAD) {
return handleStreamResponse(
response: streamedResponse,
requestAPIName: requestAPIName,
onStatusCodeError: onStatusCodeError,
);
} else {
return handleResponse(
response: response,
requestAPIName: requestAPIName,
onStatusCodeError: onStatusCodeError,
);
}
} on Exception catch (e) {
throw e;
}

/// Handing Response
} else {
throw errorInternetNotAvailable;
}
}

Handling response:

Future handleResponse({
required Response response,
HttpResponseType responseType = HttpResponseType.JSON,
required String requestAPIName,
void Function(int)? onStatusCodeError,
}) async {
setValue(requestAPIName, response.body);

if (/*success status code */) {
if (response.body.isEmpty) {
return jsonDecode(response.body);
} else {
if (responseType == HttpResponseType.JSON) {
return jsonDecode(response.body);
} else if (responseType == HttpResponseType.FULL_RESPONSE) {
return jsonDecode(response.body);
} else if (responseType == HttpResponseType.STRING) {
return jsonDecode(response.body);
} else if (responseType == HttpResponseType.BODY_BYTES) {
return jsonDecode(response.body);
}
}
} else {
if (response.body.isJson) log(jsonDecode(response.body));
if (response.body.isJson) return jsonDecode(response.body);
throw handleErrorCode(response.statusCode, onStatusCodeError);
}
}

Making final response :

Future<UserRegisterResponse> registerUser({
required Map<String, dynamic> request,
}) async {
return UserRegisterResponse.fromJson(
await BaseApi.request(
requestBody: request, endPoint: '/api/registerUser', type: HttpRequestMethod.POST,
),
);
}

The return type is the response of the model class

--

--

Scaibu
Scaibu

Written by Scaibu

Revolutionize Education with Scaibu: Improving Tech Education and Building Networks with Investors for a Better Future

No responses yet