serverpod / serverpod

Serverpod is a next-generation app and web server, explicitly built for the Flutter and Dart ecosystem.
BSD 3-Clause "New" or "Revised" License
2.46k stars 230 forks source link

Add abstraction of requests and responses in Relic #2495

Open vlidholt opened 1 month ago

vlidholt commented 1 month ago

Relic is Serverpod's built-in web server. Adding an abstraction layer on top of dart:io could be beneficial for a number of reasons. It would make it easier to work with Relic and make the interface future-proof if we want to move away from dart:io.

The shelf package has done a pretty good job with this, but it has some shortcomings. We could create a new package based on shelf (to preserve its licence, and give them proper credit). We can then tighten up some of its shortcomings. The new package could be named serverpod_relic_helpers or if we come up with a better name. From the shelf package we can copy and modify the following classes: Message, Request, Response, and Body.

The most significant issues with the types from shelf are that they are largely untyped (my guess because of legacy), and they are using List<int> to represent data (which is much less efficient than using Uint8List). Adding type-safety and using Uint8List will improve performance and memory usage (especially for large requests).

Modifications to the shelf Body class

Instead of having a generic constructor that takes any type of object, we could have three distinct, typed constructors:

Body.fromString(String body, {Encoding? encoding});

Body.fromDataStream(Stream<Uint8List> body);

Body.fromData(Uint8List body);

The underlying stream can be accessed through either the read method, which should return a Stream<Uint8List> (instead of the Stream<List<int>>) or readAsString, which decodes the full stream into a String.

Modifications to the shelf Request class

We can take the opportunity to add the parameters that are parsed by the new Router (#2489) to the Request class, making them easy to access:

Map<String, String> pathParameters;

Modifications to Relic's Route class

To support the new abstractions, the handleRequest method of the Route class can be structured like this:

Future<Response> handleRequest(Session session, Request request);
SandPod commented 1 month ago

My understanding is that the biggest shortcoming of shelf is that it does not provide type-safety and uses List<int>´ instead ofUint8List`.

How big of an undertaking is it to introduce these changes? Is there any possibility for us to add these changes as contributions directly to shelf instead of creating a fork?

We kind of end up needing to copy or mimic the classes regardless if we want an abstraction layer, but it could help us make it smaller.