Skip to content

Commit 25f7d34

Browse files
committed
feat: logging
1 parent c5a37b9 commit 25f7d34

File tree

3 files changed

+300
-3
lines changed

3 files changed

+300
-3
lines changed

lib/cognito/auth_api_http_client.dart

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
2+
3+
part of devspace;
4+
5+
// ignore: camel_case_types
6+
enum kAuthRequirement
7+
{
8+
none,
9+
required,
10+
optional,
11+
}
12+
13+
// ignore: camel_case_types
14+
enum kHttpMethod
15+
{
16+
get,
17+
post,
18+
put,
19+
delete,
20+
}
21+
22+
class HttpStatusCodeInterpreter {
23+
24+
final int statusCode;
25+
26+
HttpStatusCodeInterpreter({
27+
required this.statusCode,
28+
});
29+
30+
bool get isSuccess => statusCode >= 200 && statusCode < 300;
31+
bool get isUnauthorized => statusCode == 401;
32+
33+
34+
}
35+
36+
class AuthApiResponse extends HttpStatusCodeInterpreter {
37+
38+
final Map<String, dynamic>? body;
39+
40+
AuthApiResponse({
41+
required int statusCode,
42+
required this.body,
43+
}) : super(statusCode: statusCode);
44+
45+
bool get hasBody => body != null;
46+
47+
}
48+
49+
50+
typedef GetAuthToken = Future<String?> Function();
51+
52+
class UserNotAuthorizedException implements Exception {
53+
final dynamic message;
54+
55+
UserNotAuthorizedException({
56+
this.message = 'User is not authorized',
57+
});
58+
59+
}
60+
61+
class AuthApiHttpClient {
62+
63+
final String baseUrl;
64+
final GetAuthToken onGetAuthToken;
65+
66+
AuthApiHttpClient({
67+
required this.baseUrl,
68+
required this.onGetAuthToken,
69+
});
70+
71+
Future<AuthApiResponse> post({
72+
required String apiPath,
73+
required Map<String, dynamic> body,
74+
Map<String, String> additionaHeaders = const {},
75+
kAuthRequirement authRequirement = kAuthRequirement.required,
76+
}) async
77+
{
78+
return makeRequest(
79+
apiPath: apiPath,
80+
body: body,
81+
additionaHeaders: additionaHeaders,
82+
authRequirement: authRequirement,
83+
method: kHttpMethod.post,
84+
);
85+
}
86+
87+
Future<AuthApiResponse> get({
88+
required String apiPath,
89+
Map<String, String> additionaHeaders = const {},
90+
kAuthRequirement authRequirement = kAuthRequirement.required,
91+
}) async
92+
{
93+
return makeRequest(
94+
apiPath: apiPath,
95+
body: null,
96+
additionaHeaders: additionaHeaders,
97+
authRequirement: authRequirement,
98+
method: kHttpMethod.get,
99+
);
100+
}
101+
102+
Future<AuthApiResponse> put({
103+
required String apiPath,
104+
required Map<String, dynamic> body,
105+
Map<String, String> additionaHeaders = const {},
106+
kAuthRequirement authRequirement = kAuthRequirement.required,
107+
}) async
108+
{
109+
return makeRequest(
110+
apiPath: apiPath,
111+
body: body,
112+
additionaHeaders: additionaHeaders,
113+
authRequirement: authRequirement,
114+
method: kHttpMethod.put,
115+
);
116+
}
117+
118+
Future<AuthApiResponse> delete({
119+
required String apiPath,
120+
required Map<String, dynamic> body,
121+
Map<String, String> additionaHeaders = const {},
122+
kAuthRequirement authRequirement = kAuthRequirement.required,
123+
}) async
124+
{
125+
return makeRequest(
126+
apiPath: apiPath,
127+
body: body,
128+
additionaHeaders: additionaHeaders,
129+
authRequirement: authRequirement,
130+
method: kHttpMethod.delete,
131+
);
132+
}
133+
134+
135+
136+
137+
138+
Future<AuthApiResponse> makeRequest({
139+
required String apiPath,
140+
required Map<String, dynamic>? body,
141+
Map<String, String> additionaHeaders = const {},
142+
kAuthRequirement authRequirement = kAuthRequirement.required,
143+
required kHttpMethod method,
144+
}) async
145+
{
146+
Dev.log(this, '$method to $apiPath', body);
147+
148+
try
149+
{
150+
Map<String, String> headers = await createHeaders(
151+
additionalHeaders: additionaHeaders,
152+
authRequirement: authRequirement
153+
);
154+
155+
String? jsonBody = body != null ? json.encode(body) : null;
156+
final finalUrl = path.join(baseUrl, apiPath);
157+
final uri = Uri.parse(finalUrl);
158+
159+
http.Response? response;
160+
161+
switch (method)
162+
{
163+
case kHttpMethod.get:
164+
response = await http.get(
165+
uri,
166+
headers: headers,
167+
);
168+
break;
169+
case kHttpMethod.post:
170+
response = await http.post(
171+
uri,
172+
headers: headers,
173+
body: jsonBody,
174+
);
175+
break;
176+
case kHttpMethod.put:
177+
response = await http.put(
178+
uri,
179+
headers: headers,
180+
body: jsonBody,
181+
);
182+
break;
183+
case kHttpMethod.delete:
184+
response = await http.delete(
185+
uri,
186+
headers: headers,
187+
body: jsonBody,
188+
);
189+
break;
190+
}
191+
192+
if (response.statusCode >= 200 && response.statusCode < 300)
193+
{
194+
final jsonResponse = response.body.isNotEmpty && response.headers['content-type']?.contains('application/json') == true
195+
? json.decode(response.body)
196+
: null;
197+
198+
return AuthApiResponse(
199+
statusCode: response.statusCode,
200+
body: jsonResponse,
201+
);
202+
}
203+
else
204+
{
205+
Dev.logError(this, 'Request failed with status: ${response.statusCode}.', response);
206+
207+
return AuthApiResponse(
208+
statusCode: response.statusCode,
209+
body: null,
210+
);
211+
}
212+
}
213+
catch (e)
214+
{
215+
Dev.logException(this, e, 'Failed $method to $apiPath');
216+
217+
if (e is UserNotAuthorizedException)
218+
{
219+
return AuthApiResponse(
220+
statusCode: 401,
221+
body: null,
222+
);
223+
}
224+
225+
return AuthApiResponse(
226+
statusCode: 500,
227+
body: null,
228+
);
229+
}
230+
}
231+
232+
233+
234+
235+
236+
237+
238+
239+
240+
Future<Map<String, String>> createHeaders({
241+
required Map<String, String> additionalHeaders,
242+
required kAuthRequirement authRequirement,
243+
}) async
244+
{
245+
Map<String, String> headers = {
246+
'Content-Type': 'application/json',
247+
};
248+
249+
headers.addAll(additionalHeaders);
250+
251+
if (authRequirement != kAuthRequirement.none)
252+
{
253+
final token = await onGetAuthToken();
254+
255+
if (token == null)
256+
{
257+
if (authRequirement == kAuthRequirement.required)
258+
{
259+
throw UserNotAuthorizedException();
260+
}
261+
}
262+
else
263+
{
264+
headers['Authorization'] = 'Bearer $token';
265+
}
266+
}
267+
268+
269+
return headers;
270+
}
271+
272+
}

lib/core/diagnostics/dev.dart

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,27 @@ abstract class Dev
1010
String className = (issuer is String) ? issuer : issuer.runtimeType.toString();
1111

1212
String finalMessage = message != null ? 'EXCEPTION [$className]: $message' : 'EXCEPTION [$className]';
13-
log(finalMessage, error: exception, stackTrace: StackTrace.current);
13+
developer.log(finalMessage, error: exception, stackTrace: StackTrace.current);
14+
}
15+
16+
static void logError(dynamic issuer, String message, [Object? object])
17+
{
18+
final finalMessage = object != null ? '$message\n$object' : message;
19+
String className = (issuer is String) ? issuer : issuer.runtimeType.toString();
20+
developer.log('ERROR [$className]: $finalMessage');
21+
}
22+
23+
static void logWarning(dynamic issuer, String message, [Object? object])
24+
{
25+
final finalMessage = object != null ? '$message\n$object' : message;
26+
String className = (issuer is String) ? issuer : issuer.runtimeType.toString();
27+
developer.log('WARNING [$className]: $finalMessage');
28+
}
29+
30+
static void log(dynamic issuer, String message, [Object? object])
31+
{
32+
final finalMessage = object != null ? '$message\n$object' : message;
33+
String className = (issuer is String) ? issuer : issuer.runtimeType.toString();
34+
developer.log('info [$className]: $finalMessage');
1435
}
1536
}

lib/devspace.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
library devspace;
22

33
import 'dart:async';
4-
import 'dart:developer';
4+
import 'dart:developer' as developer;
55
import 'dart:io';
66
import 'dart:math' as math;
77
import 'dart:ui';
@@ -11,8 +11,11 @@ import 'package:flutter/foundation.dart';
1111
import 'package:flutter/foundation.dart' as foundation;
1212
import 'package:flutter/material.dart';
1313
import 'package:flutter/material.dart' as material;
14-
import 'package:flutter/services.dart';
1514
import 'package:flutter/widgets.dart' as widgets;
15+
import 'package:http/http.dart' as http;
16+
import 'package:http/http.dart';
17+
import 'dart:convert';
18+
import 'package:path/path.dart' as path;
1619

1720
import 'package:get_it/get_it.dart';
1821
import 'package:go_router/go_router.dart';
@@ -176,6 +179,7 @@ part 'brixies/steps_indicator.dart';
176179

177180
// cognito
178181

182+
part 'cognito/auth_api_http_client.dart';
179183
part 'cognito/cognito_service.dart';
180184

181185
// common

0 commit comments

Comments
 (0)