From b6ad8859c2783a4ae734f59a0f322b9d7c3b75fa Mon Sep 17 00:00:00 2001 From: Seven Du Date: Wed, 1 May 2024 00:38:06 +0800 Subject: [PATCH] feat(spry): Support `request.fetch`, see `webfetch` fetch function. --- .github/dependabot.yml | 6 - README.md | 4 +- bun.lockb | Bin 43178 -> 47639 bytes docs/basics/request.md | 19 ++++ package.json | 5 +- packages/spry/CHANGELOG.md | 19 ++++ packages/spry/example/main.dart | 3 + packages/spry/lib/spry.dart | 1 + .../spry/lib/src/request/request+fetch.dart | 105 ++++++++++++++++++ packages/spry/pubspec.yaml | 4 +- 10 files changed, 154 insertions(+), 12 deletions(-) create mode 100644 packages/spry/lib/src/request/request+fetch.dart diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 34864c2..2a1dba6 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,12 +5,6 @@ updates: schedule: interval: daily - # docs - - package-ecosystem: npm - directory: / - schedule: - interval: daily - # spry - package-ecosystem: pub directory: /packages/spry diff --git a/README.md b/README.md index 7478ab7..b0a05fb 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ Spry is an HTTP middleware framework for Dart to make web applications and APIs ```dart import 'package:spry/spry.dart'; -final app = Application.late(); - main() async { + final app = Application.late(); + app.get("hello", (request) => "Hello, Spry!"); await app.run(port: 3000); diff --git a/bun.lockb b/bun.lockb index 2245ce527e22900aca6a9c516858331c7f7033e2..86964ca658d91ba6da2eafb08470fcfa816e9089 100755 GIT binary patch literal 47639 zcmeHw2{@Ep`1jBxk}N4{vle3Pi3q8XEQv}~3#(5g{rq zC|Xo16qOe7-DhSV^YBLE|9#j0yROcA-S3%m?sNaneeSb9=NugwDU|>QUB#K|qeAfs zlyna884g79qPcjwQN1W6HyYiW>`w|*9nMW45Yj~H`f5#PRtYL;M1eI0#lE$^n$-@Q z7*pJjH?3YKm>QV_iNN`@JOXbIKa?GoWw3vA^Y{pa(7*r+GcK5mKoEuSOYnuk_h9>> zpoR#9^&rd-{$~gafd7W=Q+)iX{!|L1iXFCtbV9)2PGsS{1YZ!sE)0f$urGyR!p8Nb zG5jHp&^nYr7!G_NvJZ{wN+4uFcm#y6@DK>&!4IVRGZl1WPy!(@2A$^R72r!CyaeSZ z0>2Ra3E-b#hj)W74q*oPlfbtEUlx27@Fl?)X2&;ysbnBr0=_i(r@)s0e<$1b1s};< zv%}NCNBN8cAL%6kKC%Oa;T%BqawQ0Zk&vA_z<8s;e+NFY=VS0ud_Fsz$>t}qB#J`8Teul)?~*^fsb$n*!-VhWQ6+$e3VZG_(=XL_$XZ(_@lv(W%Jjw`JU|X zQt**H!-MKcg%;oggv!$lKB^CIGTl>oC4*4U4*QdxoypE#lnMx={Gi>CTq)jE^>GBk zNC@A8cvNpiU>txBJr6!gcMjq~<)Gke*giM-V6vq@ORvxBTcxElj zTW|TCR(oj$zsEPK=85tY!P&;uf-@Vnc~2|dj27OTyGpB_60*&tCUr`!2bWofoz7SP z5&Xe1yH6$0(IT&_i(f`AEB;{48^+jT+Ho#bcCDk8gsgPl!)<#n%s&jlQ|a)%Mx762kRYa9@7V%v&oYGjsN;VXfI(<|P-BqtC7871me0$hD{B_SaB}wMQ1k+^FAu ze3Y0;Ta4}pnUy>CZQe{g>ES3mBk0Xu|CVHfua}(1wDSo{h<^2QO6h#KJ7?BZ5qS-+ zZ7-86l7%Mb%Qsl18&j9l4df1_q=l?(;+=f2dV`y>+TN-g)EvFznmpdG^9W5QQyRDp z1;pkw96TLZsA{y&F`Gw_``~!h-1`kK_G5qiP+M56MOmm{t~g<$@Uh#&7Q`99_0D_t z>{?>F`W2mtSG<}OZRc!wmwHI+WVOE7s)CYE$48Wd=E1rl6?GbV;ujC586?Yp;{ARy za7jaZ!{mYlE4yD0ckcC@okqT} c^b$gg@+oe+n3{t~YCz9&(+su}6=h(SfmrbFI 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 literal 43178 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 It also supports you to ignore HTTP schema and host, and directly use path to obtain data from other handlers + +```dart +// Remote with fetch +app.get('github/:name', (request) { + return request.fetch('https://api.github.com/users/${request.param('name')}'); +}); + +// Fetch profile +app.get('users/:id', (request) => ...); +app.get('profile/:id', (request) { + return request.fetch('/users/${request.param('id')}'); +}); +``` diff --git a/package.json b/package.json index 8e891d6..d85aa42 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { + "private": true, "scripts": { "docs:dev": "vitepress dev docs", "docs:build": "vitepress build docs", "docs:preview": "vitepress preview docs" }, - "devDependencies": { - "vitepress": "^1.0.0-rc.36" + "dependencies": { + "vitepress": "^1.1.4" } } diff --git a/packages/spry/CHANGELOG.md b/packages/spry/CHANGELOG.md index 3e400dc..455758f 100644 --- a/packages/spry/CHANGELOG.md +++ b/packages/spry/CHANGELOG.md @@ -1,3 +1,22 @@ +# Spry v3.3.0 + +To install Spry v3.3.0 run the following command: + +```bash +dart pub add spry:3.3.0 +``` + +or update your `pubspec.yaml` file: + +```yaml +dependencies: + spry: ^3.3.0 +``` + +## What's Changed + +- **Feature**: Support `request.fetch`, see `webfetch` fetch function. + # Spry v3.2.3 To install Spry v3.2.3 run the following command: diff --git a/packages/spry/example/main.dart b/packages/spry/example/main.dart index 46d00d4..47968a4 100644 --- a/packages/spry/example/main.dart +++ b/packages/spry/example/main.dart @@ -4,6 +4,9 @@ final app = Application.late(); void main(List args) async { app.get('hello', (request) => 'Hello, Spry!'); + app.get('test', (request) { + return request.fetch('/hello'); + }); await app.run(port: 3000); diff --git a/packages/spry/lib/spry.dart b/packages/spry/lib/spry.dart index 7d09973..1d07379 100644 --- a/packages/spry/lib/spry.dart +++ b/packages/spry/lib/spry.dart @@ -37,6 +37,7 @@ export 'src/request/request+route.dart'; export 'src/request/request+search_params.dart'; export 'src/request/request+json.dart'; export 'src/request/request+text.dart'; +export 'src/request/request+fetch.dart' show Request$Fetch; // Response export 'src/response/response+is_closed.dart'; diff --git a/packages/spry/lib/src/request/request+fetch.dart b/packages/spry/lib/src/request/request+fetch.dart new file mode 100644 index 0000000..eda1efc --- /dev/null +++ b/packages/spry/lib/src/request/request+fetch.dart @@ -0,0 +1,105 @@ +// ignore_for_file: file_names + +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:webfetch/webfetch.dart' hide fetch; +import 'package:webfetch/webfetch.dart' as webfetch show fetch, Client; + +import '../_internal/map+value_of.dart'; +import 'request+locals.dart'; + +extension Request$Fetch on HttpRequest { + Fetch get fetch => webfetch.fetch.use(client); +} + +extension on HttpRequest { + static const key = #spry.request.fetch.client; + + webfetch.Client get client { + return locals.valueOf(key, (_) { + return locals[key] = FetchClient(requestedUri); + }); + } +} + +class FetchClient implements webfetch.Client { + final Uri base; + + const FetchClient(this.base); + + @override + Future send(Request request, {bool keepalive = false}) { + return webfetch.fetch( + URL(request.url, base), + keepalive: keepalive, + method: request.method, + headers: request.headers, + body: request.body, + ); + } +} + +class SpryFetchRequest implements Request { + const SpryFetchRequest(this.request, this.url); + + final Request request; + + @override + final String url; + + @override + Future arrayBuffer() => request.arrayBuffer(); + + @override + Future blob() => request.blob(); + + @override + Stream? get body => request.body; + + @override + bool get bodyUsed => request.bodyUsed; + + @override + RequestCache get cache => request.cache; + + @override + Request clone() => SpryFetchRequest(request.clone(), url); + + @override + RequestCredentials get credentials => request.credentials; + + @override + RequestDestination get destination => request.destination; + + @override + Future formData() => request.formData(); + + @override + Headers get headers => request.headers; + + @override + String get integrity => request.integrity; + + @override + Future json() => request.json(); + + @override + String get method => request.method; + + @override + RequestMode get mode => request.mode; + + @override + RequestRedirect get redirect => request.redirect; + + @override + String get referrer => request.referrer; + + @override + ReferrerPolicy get referrerPolicy => request.referrerPolicy; + + @override + Future text() => request.text(); +} diff --git a/packages/spry/pubspec.yaml b/packages/spry/pubspec.yaml index e75c3a9..46a2bda 100644 --- a/packages/spry/pubspec.yaml +++ b/packages/spry/pubspec.yaml @@ -1,6 +1,6 @@ name: spry description: Spry is an HTTP middleware framework for Dart to make web applications and APIs server more enjoyable to write. -version: 3.2.3 +version: 3.3.0 homepage: https://spry.fun repository: https://github.com/medz/spry @@ -11,7 +11,7 @@ dependencies: logging: ^1.2.0 path: ^1.9.0 routingkit: ^0.2.0 - webfetch: ^0.0.15 + webfetch: ^0.0.16 dev_dependencies: lints: ^3.0.0