spooder 4.2.15 → 4.2.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +50 -1
  2. package/package.json +1 -1
  3. package/src/api.ts +18 -2
package/README.md CHANGED
@@ -47,6 +47,8 @@ The `CLI` component of `spooder` is a global command-line tool for running serve
47
47
  - [`server.default(handler: DefaultHandler)`](#api-routing-server-default)
48
48
  - [`server.error(handler: ErrorHandler)`](#api-routing-server-error)
49
49
  - [`server.on_slow_request(callback: SlowRequestCallback, threshold: number)`](#api-routing-server-on-slow-request)
50
+ - [API > Routing > Validation](#api-routing-validation)
51
+ - [`validate_req_json(handler: JSONRequestHandler)`](#api-routing-validate-req-json)
50
52
  - [API > Routing > Directory Serving](#api-routing-directory-serving)
51
53
  - [`server.dir(path: string, dir: string, handler?: DirHandler, method: HTTP_METHODS)`](#api-routing-server-dir)
52
54
  - [API > Routing > Server-Sent Events](#api-routing-server-sent-events)
@@ -676,7 +678,7 @@ By default requests that take longer than `1000ms` to process will trigger the c
676
678
  > If your canary reports to a public repository, be cautious about directly including the `req` object in the callback. This can lead to sensitive information being leaked.
677
679
 
678
680
  ```ts
679
- server.on_slow_request(async (req, time) => {
681
+ server.on_slow_request(async (req, time, url) => {
680
682
  // avoid `time` in the title to avoid canary spam
681
683
  // see caution() API for information
682
684
  await caution('Slow request warning', { req, time });
@@ -686,6 +688,53 @@ server.on_slow_request(async (req, time) => {
686
688
  > [!NOTE]
687
689
  > The callback is not awaited internally, so you can use `async/await` freely without blocking the server/request.
688
690
 
691
+ <a id="api-routing-validation"></a>
692
+ ## API > Routing > Validation
693
+
694
+ <a id="api-routing-validate-req-json"></a>
695
+ ### 🔧 `validate_req_json(handler: JSONRequestHandler)`
696
+
697
+ In the scenario that you're expecting an endpoint to receive JSON data, you might set up a handler like this:
698
+
699
+ ```ts
700
+ server.route('/api/endpoint', async (req, url) => {
701
+ const json = await req.json();
702
+ // do something with json.
703
+ return 200;
704
+ })
705
+ ```
706
+
707
+ The problem with this is that if the request body is not valid JSON, the server will throw an error (potentially triggering canary reports) and return a `500` response.
708
+
709
+ What should instead happen is something like this:
710
+
711
+ ```ts
712
+ server.route('/api/endpoint', async (req, url) => {
713
+ // check content-type header
714
+ if (req.headers.get('Content-Type') !== 'application/json')
715
+ return 400;
716
+
717
+ try {
718
+ const json = await req.json();
719
+ // do something with json.
720
+ return 200;
721
+ } catch (err) {
722
+ return 400;
723
+ }
724
+ })
725
+ ```
726
+
727
+ As you can see this is quite verbose and adds a lot of boilerplate to your handlers. `validate_req_json` can be used to simplify this.
728
+
729
+ ```ts
730
+ server.route('/api/endpoint', validate_req_json(async (json, req, url) => {
731
+ // do something with json.
732
+ return 200;
733
+ }));
734
+ ```
735
+
736
+ This behaves the same as the code above, where a `400` status code is returned if the `Content-Type` header is not `application/json` or if the request body is not valid JSON, and no error is thrown.
737
+
689
738
  <a id="api-routing-directory-serving"></a>
690
739
  ## API > Routing > Directory Serving
691
740
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "spooder",
3
3
  "type": "module",
4
- "version": "4.2.15",
4
+ "version": "4.2.17",
5
5
  "exports": {
6
6
  ".": {
7
7
  "bun": "./src/api.ts",
package/src/api.ts CHANGED
@@ -398,6 +398,8 @@ type ErrorHandler = (err: Error, req: Request, url: URL) => Resolvable<Response>
398
398
  type DefaultHandler = (req: Request, status_code: number) => HandlerReturnType;
399
399
  type StatusCodeHandler = (req: Request) => HandlerReturnType;
400
400
 
401
+ type JSONRequestHandler = (req: Request, url: URL, json: JsonSerializable) => HandlerReturnType;
402
+
401
403
  type ServerSentEventClient = {
402
404
  message: (message: string) => void;
403
405
  event: (event_name: string, message: string) => void;
@@ -442,6 +444,20 @@ function route_directory(route_path: string, dir: string, handler: DirHandler):
442
444
  };
443
445
  }
444
446
 
447
+ export function validate_req_json(JSONRequestHandler: JSONRequestHandler): RequestHandler {
448
+ return async (req: Request, url: URL) => {
449
+ try {
450
+ // validate content type header
451
+ if (req.headers.get('Content-Type') !== 'application/json')
452
+ return 400; // Bad Request
453
+
454
+ return JSONRequestHandler(req, url, await req.json());
455
+ } catch (e) {
456
+ return 400; // Bad Request
457
+ }
458
+ };
459
+ }
460
+
445
461
  function format_query_parameters(search_params: URLSearchParams): string {
446
462
  let result_parts = [];
447
463
 
@@ -586,7 +602,7 @@ export function serve(port: number) {
586
602
  }
587
603
  }
588
604
 
589
- type SlowRequestCallback = (req: Request, request_time: number) => void;
605
+ type SlowRequestCallback = (req: Request, request_time: number, url: URL) => void;
590
606
 
591
607
  let slow_request_callback: SlowRequestCallback | null = null;
592
608
  let slow_request_threshold: number = 1000;
@@ -603,7 +619,7 @@ export function serve(port: number) {
603
619
  const request_time = Date.now() - request_start;
604
620
 
605
621
  if (slow_request_callback !== null && request_time > slow_request_threshold)
606
- slow_request_callback(req, request_time);
622
+ slow_request_callback(req, request_time, url);
607
623
 
608
624
  return print_request_info(req, response, url, request_time);
609
625
  }