Last active
December 4, 2023 23:19
-
-
Save kenreilly/598c3b324a64d173516f4f52ce8344d2 to your computer and use it in GitHub Desktop.
Dart Metaprogramming - API Service
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:io'; | |
import 'dart:convert'; | |
import 'dart:mirrors'; | |
import 'package:api_sdk/framework/api-method.dart'; | |
import 'package:api_sdk/framework/api-route.dart'; | |
import 'package:http_server/http_server.dart'; | |
abstract class ServiceBase { | |
InstanceMirror _self; | |
ServiceBase() { _self = reflect(this); } | |
void dispose() => _self = null; | |
} | |
class RESTSession { | |
final HttpRequestBody body; | |
RESTSession(this.body); | |
} | |
abstract class APIService extends ServiceBase { | |
static final List<APIService> _instances = []; | |
static final List<APIRoute> _routes = []; | |
RoutePath _route = RoutePath('/'); | |
APIService(): super() { | |
_instances.add(this); | |
_self.type.metadata.forEach((m) => (m.reflectee is RoutePath) ? (_route = _route + m.reflectee) : null); | |
_self.type.declarations.forEach((Symbol s, DeclarationMirror m) { if (m is MethodMirror) (_load(s, m)); }); | |
} | |
@override | |
void dispose() { | |
_instances.remove(this); | |
super.dispose(); | |
} | |
static void onRequest(HttpRequestBody reqbody) async { | |
HttpResponse response = reqbody.request.response; | |
APIRoute route = await _routes.firstWhere((route) => route.check(reqbody.request), orElse: () => null); | |
if (route == null) { | |
await (response..statusCode = 404)..write('NotFound'); | |
await response.close(); | |
return; | |
} | |
if (route.verb == 'WS') { return route.upgrade(reqbody); } | |
try { | |
dynamic data = await route.handle(reqbody); | |
response.statusCode = 200; | |
if (data is String) { | |
response.write(data); | |
} | |
else if (data is File) { | |
List<int> bytes = await data.readAsBytes(); | |
response.write(base64.encode(bytes)); | |
} | |
else { | |
await response.add(data); | |
} | |
} catch(e) { | |
response.addError(e); | |
} | |
await response.close(); | |
} | |
void _load(Symbol s, MethodMirror m) { | |
if (m.metadata.isEmpty) return; | |
String _verb; | |
RoutePath _path; | |
bool _json; | |
m.metadata.forEach((InstanceMirror i) { | |
if (i.reflectee == JSON) { _json = true; } | |
else if (i.reflectee is APIMethod) { | |
_verb = MirrorSystem.getName(i.type.simpleName); | |
_path = _route + RoutePath(i.reflectee.route); | |
} | |
}); | |
_routes.add(APIRoute(this, _verb, _path, m, json: _json)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment