Skip to content

Instantly share code, notes, and snippets.

@wonderkidshihab
Last active January 4, 2024 19:10
Show Gist options
  • Save wonderkidshihab/c62e7b069c8ad7704cec265d013b4c05 to your computer and use it in GitHub Desktop.
Save wonderkidshihab/c62e7b069c8ad7704cec265d013b4c05 to your computer and use it in GitHub Desktop.
Api client

api_client.dart is for projects with dart version lower than 3 and api_client_v2.dart is updated for dart 3.

API Client and API Client Without Authentication Documentation

Overview

This Dart code provides two classes ApiClient and ApiClientWithoutAuth that can be used to perform RESTful API calls with and without authentication, respectively. The ApiClient class is used when you want to include authentication token in your API requests and ApiClientWithoutAuth when no authentication token is needed.

Both classes have methods to perform GET, POST, PUT, DELETE and a special request to handle file upload.

ApiClient Class

Initialization

This class is a singleton, meaning only one instance of it will ever exist. Use ApiClient.instance to access the instance. Before using this class, it must be initialized using the init static method:

await ApiClient.init();

This will set up the base URL, connection timeout, receive timeout, and default headers for the requests.

Methods

  • get: This method takes a URL and an optional parameters map, and performs a GET request to the given URL.
var response = await ApiClient.instance.get(url: "your_api_endpoint", params: yourParametersMap);
  • post: This method takes a URL and an optional body map, and performs a POST request to the given URL.
var response = await ApiClient.instance.post(url: "your_api_endpoint", body: yourBodyMap);
  • put: Similar to post, this method is for performing PUT requests.
var response = await ApiClient.instance.put(url: "your_api_endpoint", body: yourBodyMap);
  • delete: Similar to get, this method is for performing DELETE requests.
var response = await ApiClient.instance.delete(url: "your_api_endpoint", body: yourBodyMap);
  • requestWithFile: This method takes a URL, an optional body map, and a list of files. It performs a POST request to the given URL with the files included in the request's body.
var response = await ApiClient.instance.requestWithFile(url: "your_api_endpoint", body: yourBodyMap, files: yourFilesList);

ApiClientWithoutAuth Class

The methods and their usage in the ApiClientWithoutAuth class are similar to the ApiClient class. The difference is that requests made using this class won't include an authentication token in the headers. To access the singleton instance of this class, use ApiClientWithoutAuth.instance.

Return Values

All the methods return a Future that resolves to a tuple containing error and result fields. If the request is successful, result will contain the response data and error will be null. In case of an error, result will be null and error will contain the error details.

For example:

var response = await ApiClient.instance.get(url: "your_api_endpoint", params: yourParametersMap);
if(response.error != null) {
  print("Error occurred: ${response.error}");
} else {
  print("Received response: ${response.result}");
}

Error Handling

In case of any error during the request, such as a network error or a server error, the error will be caught and logged. The error details will also be returned in the error field of the response tuple.

/// Add dio and dio_pretty_logger into your pubspec.yaml
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
import 'package:shared_preferences/shared_preferences.dart';
const String base_url = "";
class ApiClient {
static final Dio dio = Dio();
static final ApiClient _instance = ApiClient._internal();
static ApiClient get instance => _instance;
factory ApiClient() {
return _instance;
}
ApiClient._internal();
static init() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
dio.options.baseUrl = base_url;
dio.options.connectTimeout = 60000;
dio.options.receiveTimeout = 60000;
dio.options.headers = {
HttpHeaders.acceptHeader: "application/json",
HttpHeaders.contentTypeHeader: "application/json",
if (prefs.getString("token") != null)
"Authorization": "Bearer ${prefs.getString("token")}",
};
dio.interceptors
.add(PrettyDioLogger(requestBody: true, requestHeader: true));
dio.interceptors
.add(InterceptorsWrapper(onRequest: (RequestOptions options, handler) {
return handler.next(options);
}, onResponse: (Response response, handler) {
return handler.next(response);
}, onError: (DioError e, handler) {
return handler.next(e);
}));
}
Future get({required String url, Map<String, dynamic>? params}) async {
try {
final response = await dio.get(url, queryParameters: params);
return response.data;
} on DioError {
return null;
}
}
Future post({required String url, Map<String, dynamic>? body}) async {
try {
final response = await dio.post(url, data: body);
return response.data;
} on DioError {
return null;
}
}
Future put({required String url, Map<String, dynamic>? body}) async {
try {
final response = await dio.put(url, data: body);
return response.data;
} on DioError {
return null;
}
}
Future delete({required String url, Map<String, dynamic>? body}) async {
try {
final response = await dio.delete(url, data: body);
return response.data;
} on DioError {
return null;
}
}
Future requestWithFile(
{required String url,
Map<String, dynamic>? body,
required List<File> files}) async {
try {
FormData formData = FormData.fromMap(body ?? {});
for (File file in files) {
formData.files.add(MapEntry(
"file",
await MultipartFile.fromFile(file.path,
filename: file.path.split("/").last)));
}
final response = await dio.post(url, data: formData);
return response.data;
} on DioError {
return null;
}
}
}
import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
// ignore: constant_identifier_names
const String BASEURL = "http://127.0.0.1:8000/api/";
class ApiClient {
static final Dio dio = Dio();
static final ApiClient _instance = ApiClient._internal();
static ApiClient get instance => _instance;
factory ApiClient() {
return _instance;
}
ApiClient._internal();
static Future<ApiClient> init() async {
dio.options.baseUrl = BASEURL;
dio.options.connectTimeout = const Duration(seconds: 60);
dio.options.receiveTimeout = const Duration(seconds: 60);
dio.options.headers = {
HttpHeaders.acceptHeader: "application/json",
HttpHeaders.contentTypeHeader: "application/json",
};
await _addInterceptors();
return _instance;
}
static Future<void> _addInterceptors() async {
final prefs = await SharedPreferences.getInstance();
dio.interceptors
.add(InterceptorsWrapper(onRequest: (RequestOptions options, handler) {
if (prefs.getString("access") != null) {
options.headers["Authorization"] =
"Bearer ${prefs.getString("access")}";
kDebugMode ? log("Token: ${prefs.getString("access")}") : null;
}
log(options.data.toString(), name: "Request Data");
log(options.headers.toString(), name: "Request Headers");
return handler.next(options);
}, onResponse: (Response response, handler) {
log(response.data.toString(), name: "Response Data");
return handler.next(response);
}, onError: (DioError e, handler) {
log(e.toString(), name: "Error");
log(e.response?.data.toString() ?? "", name: "Error Data");
return handler.next(e);
}));
}
Future<({String? error, dynamic result})> get({required String url, Map<String, dynamic>? params}) async {
try {
final response = await dio.get(url, queryParameters: params);
return (error: null, result: response.data);
} on DioError catch (e){
return (error: e.response?.data["detail"].toString(), result: null);
}
}
Future<({String? error, dynamic result})> post({required String url, Map<String, dynamic>? body}) async {
try {
final response = await dio.post(url, data: body);
return (error: null, result: response.data);
} on DioError catch (e){
return (error: e.response?.data["detail"].toString(), result: null);
}
}
Future<({String? error, dynamic result})> put({required String url, Map<String, dynamic>? body}) async {
try {
final response = await dio.put(url, data: body);
return (error: null, result: response.data);
} on DioError catch (e){
return (error: e.response?.data["detail"].toString(), result: null);
}
}
Future<({String? error, dynamic result})> delete({required String url, Map<String, dynamic>? body}) async {
try {
final response = await dio.delete(url, data: body);
return (error: null, result: response.data);
} on DioError catch (e){
return (error: e.response?.data["detail"].toString(), result: null);
}
}
Future<({String? error, dynamic result})> requestWithFile(
{required String url,
Map<String, dynamic>? body,
required List<MapEntry<String, File>> files}) async {
try {
FormData formData = FormData.fromMap(body ?? {});
for (var fileEntry in files) {
formData.files.add(
MapEntry(
fileEntry.key,
MultipartFile.fromFileSync(
fileEntry.value.path,
filename: fileEntry.value.path.split("/").last,
),
),
);
}
final response = await dio.post(url, data: formData);
return (error: null, result: response.data);
} on DioError catch (e) {
log(e.toString(), name: "FIle up");
return (error: e.response?.data["detail"].toString(), result: null);
}
}
}
class ApiClientWithoutAuth {
static final Dio dio = Dio(
BaseOptions(
baseUrl: BASEURL,
headers: {
HttpHeaders.acceptHeader: "application/json",
HttpHeaders.contentTypeHeader: "application/json",
},
),
);
static final ApiClientWithoutAuth _instance =
ApiClientWithoutAuth._internal();
static ApiClientWithoutAuth get instance => _instance;
factory ApiClientWithoutAuth() {
return _instance;
}
ApiClientWithoutAuth._internal();
Future get({required String url, Map<String, dynamic>? params}) async {
try {
final response = await dio.get(url, queryParameters: params);
return response.data;
} on DioError {
return null;
}
}
// Future post({required String url, Map<String, dynamic>? body}) async {
// try {
// final response = await dio.post(url, data: body);
// return response.data;
// } on DioError catch (e) {
// log(e.toString(), name: "Error");
// return null;
// }
// }
Future<({String? error, dynamic result})> post({required String url, Map<String, dynamic>? body}) async {
try {
final response = await dio.post(url, data: body);
return (error: null, result: response.data);
} on DioError catch (e){
return (error: e.response?.data["detail"].toString(), result: null);
}
}
Future<({String? error, dynamic result})> put({required String url, Map<String, dynamic>? body}) async {
try {
final response = await dio.put(url, data: body);
return (error: null, result: response.data);
} on DioError catch (e){
return (error: e.response?.data["detail"].toString(), result: null);
}
}
Future<({String? error, dynamic result})> delete({required String url, Map<String, dynamic>? body}) async {
try {
final response = await dio.delete(url, data: body);
return (error: null, result: response.data);
} on DioError catch (e){
return (error: e.response?.data["detail"].toString(), result: null);
}
}
Future<({String? error, dynamic result})> requestWithFile(
{required String url,
Map<String, dynamic>? body,
required List<MapEntry<String, File>> files}) async {
try {
FormData formData = FormData.fromMap(body ?? {});
for (var fileEntry in files) {
formData.files.add(
MapEntry(
fileEntry.key,
MultipartFile.fromFileSync(
fileEntry.value.path,
filename: fileEntry.value.path.split("/").last,
),
),
);
}
final response = await dio.post(url, data: formData);
return (error: null, result: response.data);
} on DioError catch (e) {
log(e.toString(), name: "FIle up");
return (error: e.response?.data["detail"].toString(), result: null);
}
}
}
@Murad1993h
Copy link

thank you bro

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment