Repository: VeryGoodOpenSource/dart_frog (dart)

Issue:
provider doesn't support nullable values
**Description**

I am not sure that it is a bug, as I couldn't find any community to ask it - leaving it here.
Why provider can't provide nullable values, is there any specific reason for it? 
It may be useful in some cases to have this feature.

Original code:
```  
RequestContext provide<T extends Object>(T Function() create) {
    return RequestContext._(
      request._request.change(
        context: {...request._request.context, '$T': create},
      ),
    );
  }
```

From this code I can say that '$T' on nullable value will also return string aka "MyType?" - so unfortunatelly I don't see any visible reason not to fix it

Pull request description:
<!--
  Thanks for contributing!

  Provide a description of your changes below and a general summary in the title

  Please look at the following checklist to ensure that your PR can be accepted quickly:
-->

## Status

**READY**

## Description

<!--- Describe your changes in detail -->
- feat(dart_frog): provider support nullable values (closes #688)

## Type of Change

<!--- Put an `x` in all the boxes that apply: -->

- [X] ✨ New feature (non-breaking change which adds functionality)
- [ ] 🛠️ Bug fix (non-breaking change which fixes an issue)
- [ ] ❌ Breaking change (fix or feature that would cause existing functionality to change)
- [ ] 🧹 Code refactor
- [ ] ✅ Build configuration change
- [ ] 📝 Documentation
- [ ] 🗑️ Chore

Patch:
diff --git a/packages/dart_frog/lib/src/context.dart b/packages/dart_frog/lib/src/context.dart
index 265d6e710..3a0a85fae 100644
--- a/packages/dart_frog/lib/src/context.dart
+++ b/packages/dart_frog/lib/src/context.dart
@@ -11,7 +11,7 @@ class RequestContext {
 
   /// Provide the value returned by [create] to the respective
   /// request context.
-  RequestContext provide<T extends Object>(T Function() create) {
+  RequestContext provide<T extends Object?>(T Function() create) {
     return RequestContext._(
       request._request.change(
         context: {...request._request.context, '$T': create},
diff --git a/packages/dart_frog/lib/src/provider.dart b/packages/dart_frog/lib/src/provider.dart
index a09493ee5..5ff0d6b19 100644
--- a/packages/dart_frog/lib/src/provider.dart
+++ b/packages/dart_frog/lib/src/provider.dart
@@ -1,7 +1,7 @@
 import 'package:dart_frog/dart_frog.dart';
 
 /// Provide a value to the current handler by calling [create] lazily.
-Middleware provider<T extends Object>(
+Middleware provider<T extends Object?>(
   T Function(RequestContext context) create,
 ) {
   return (handler) {


Test patch:
diff --git a/packages/dart_frog/test/src/provider_test.dart b/packages/dart_frog/test/src/provider_test.dart
index e75b4e32a..2132f6a5c 100644
--- a/packages/dart_frog/test/src/provider_test.dart
+++ b/packages/dart_frog/test/src/provider_test.dart
@@ -7,13 +7,17 @@ import 'package:test/test.dart';
 void main() {
   test('values can be provided and read via middleware', () async {
     const value = '__test_value__';
+    String? nullableValue;
     Handler middleware(Handler handler) {
-      return handler.use(provider<String>((_) => value));
+      return handler
+          .use(provider<String>((_) => value))
+          .use(provider<String?>((_) => nullableValue));
     }
 
     Response onRequest(RequestContext context) {
       final value = context.read<String>();
-      return Response(body: value);
+      final nullableValue = context.read<String?>();
+      return Response(body: '$value:$nullableValue');
     }
 
     final handler =
@@ -24,7 +28,7 @@ void main() {
     final response = await client.get(Uri.parse('http://localhost:3010/'));
 
     await expectLater(response.statusCode, equals(HttpStatus.ok));
-    await expectLater(response.body, equals(value));
+    await expectLater(response.body, equals('$value:$nullableValue'));
 
     await server.close();
   });