Skip to content

Conversation

@nielsenko
Copy link
Collaborator

@nielsenko nielsenko commented Oct 8, 2025

Description

This PR will allow relic to infer the mime-type of a body on construction, if not explicitly set. In particular html passed to Body.fromString won't be given mime-type text/plain, but other types are inferred as well. See tests for examples.

Related Issues

Pre-Launch Checklist

Please ensure that your PR meets the following requirements before submitting:

  • This update focuses on a single feature or bug fix. (For multiple fixes, please submit separate PRs.)
  • I have read and followed the Dart Style Guide and formatted the code using dart format.
  • I have referenced at least one issue this PR fixes or is related to.
  • I have updated/added relevant documentation (doc comments with ///), ensuring consistency with existing project documentation.
  • I have added new tests to verify the changes.
  • All existing and new tests pass successfully.
  • I have documented any breaking changes below.

Breaking Changes

  • Includes breaking changes.
  • No breaking changes.

Additional Notes

It is debatable if this is a breaking change. The interface doesn't change, and if you specify mimeType there is no change, but with this PR we try to infer the mimeType instead of just defaulting text/plain and application/octet-stream.

Summary by CodeRabbit

  • New Features

    • Automatic MIME type detection for text and binary bodies with sensible fallbacks; encoding aligns with inferred type when applicable.
  • Refactor

    • Removed predefined body type presets; create body types explicitly instead.
    • Updated builders to accept optional MIME type parameters instead of requiring them.
  • Documentation

    • Improved inline docs and minor input sanitization for MIME parsing.
  • Tests

    • Added comprehensive tests for MIME inference, explicit overrides, encoding defaults, and binary type detection.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 8, 2025

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Implements MIME-type inference in Body.fromString and Body.fromData when mimeType is omitted, adds helpers for text detection, integrates MimeTypeResolver for binary data, updates imports, and adjusts factory signatures. Removes predefined BodyType static constants. Adds tests covering MIME inference and explicit overrides.

Changes

Cohort / File(s) Summary of Changes
Body factories & MIME inference
lib/src/body/body.dart
- Body.fromString now accepts MimeType? and infers MIME when null via _tryInferTextMimeTypeFrom; fallback MimeType.plainText.
- Body.fromData now accepts MimeType? and infers MIME from bytes via MimeTypeResolver; fallback MimeType.octetStream.
- Added helpers _tryInferTextMimeTypeFrom, _isWhitespace and imports dart:math, package:mime/mime.dart.
- Encoding selection tied to inferred MIME where applicable.
BodyType API surface
lib/src/body/types/body_type.dart
- Removed all predefined static constants (e.g., plainText, html, json, xml, octetStream, etc.).
- Constructor/fields unchanged; instances must be constructed explicitly.
MimeType parsing/docs
lib/src/body/types/mime_type.dart
- Trim parts on parse (type/subtype).
- Added doc comments for constructor and isText.
- Minor whitespace cleanup. No signature changes.
Tests for inference
test/body/body_infer_mime_type_test.dart
- New tests validating inference for strings (JSON, HTML, XML, plain) and binaries (PNG, JPEG, GIF, PDF, fallback to octet-stream), explicit overrides, encoding behavior, and empty-data default.

Sequence Diagram(s)

sequenceDiagram
  participant C as Caller
  participant B as Body.fromString
  participant I as _tryInferTextMimeTypeFrom
  participant R as Result(Body)

  C->>B: fromString(text, encoding=?, mimeType=null)
  alt mimeType provided
    B->>R: Construct Body with provided mimeType/encoding
  else infer from text
    B->>I: Inspect prefix/whitespace
    I-->>B: Inferred MIME (json/xml/html/plain)
    B->>R: Construct Body with inferred MIME and encoding
  end
Loading
sequenceDiagram
  participant C as Caller
  participant D as Body.fromData
  participant MR as MimeTypeResolver
  participant R as Result(Body)

  C->>D: fromData(bytes, encoding=?, mimeType=null)
  alt mimeType provided
    D->>R: Construct Body with provided mimeType/encoding
  else infer from bytes
    D->>MR: lookupMimeType(bytes)
    MR-->>D: MIME or null
    D->>R: Construct Body with resolved MIME or octet-stream
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The pull request includes unrelated API changes such as removal of all public static BodyType presets and documentation-only edits, as well as inference logic for binary data bodies which are not specified by issue #190’s objective to default Body.fromString HTML to text/html. Revert or extract the BodyType static constant removals and binary data inference into separate changes and focus this PR solely on updating Body.fromString’s default MIME type behavior per issue #190.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly and accurately reflects the primary change of adding MIME type inference to Body constructors, using conventional commit style and clear, concise phrasing.
Linked Issues Check ✅ Passed The changes to Body.fromString add content-based MIME type inference, including detecting HTML, JSON, and XML, which directly satisfies and extends the requested behavior in issue [#190] for defaulting HTML content to text/html.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
Description Check ✅ Passed The pull request description includes all required sections—Description, Related Issues with a fix reference, Pre-Launch Checklist with completed items, Breaking Changes declaration, and Additional Notes—and aligns with the repository’s template. The syntax used for closing the issue and the checklist formatting match the expected guidelines. Therefore, the description meets the required structure and content.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Oct 8, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.90%. Comparing base (3dbfe36) to head (eabdd76).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #206      +/-   ##
==========================================
+ Coverage   91.85%   91.90%   +0.04%     
==========================================
  Files          85       85              
  Lines        3156     3175      +19     
  Branches     1631     1639       +8     
==========================================
+ Hits         2899     2918      +19     
  Misses        257      257              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@nielsenko
Copy link
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 8, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nielsenko nielsenko marked this pull request as ready for review October 8, 2025 10:30
@nielsenko nielsenko requested a review from a team October 8, 2025 10:30
@nielsenko nielsenko self-assigned this Oct 8, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
test/body/body_infer_mime_type_test.dart (1)

9-52: Consider adding a test for JSON array inference.

The tests comprehensively cover JSON object inference (starting with {), but there's no test verifying JSON array inference (starting with [). While the implementation in body.dart handles this case, adding a test would ensure this path is validated.

Example test to add:

test(
    'Given JSON array content without explicit mimeType, '
    'when Body.fromString is called, '
    'then it infers application/json', () {
  const jsonArrayContent = '[{"key": "value"}, {"key2": "value2"}]';
  final body = Body.fromString(jsonArrayContent);
  expect(body.bodyType?.mimeType, MimeType.json);
});
lib/src/body/body.dart (2)

78-111: Minor: Consider case-insensitive HTML tag detection.

The inference logic is well-structured and avoids unnecessary allocations. However, HTML tag detection is case-sensitive for the <html tag (line 106) while it handles DOCTYPE case variations. Although uppercase HTML tags are rare in modern code, <HTML> is technically valid HTML.

If desired, you could make the HTML tag check case-insensitive:

-    if (prefix.startsWith('<!DOCTYPE html') ||
-        prefix.startsWith('<!doctype html') ||
-        prefix.startsWith('<html')) {
+    final lowerPrefix = prefix.toLowerCase();
+    if (lowerPrefix.startsWith('<!doctype html') ||
+        lowerPrefix.startsWith('<html')) {
       return MimeType.html;
     }

Note: This adds a toLowerCase() allocation, so weigh the trade-off.


134-157: Consider defensive error handling for MIME type parsing.

The MIME type resolution logic is well-structured, but there's a potential risk: if _resolver.lookup returns an invalid MIME string (unlikely but possible), MimeType.parse will throw a FormatException and crash the factory.

While the mime package should only return valid MIME strings or null, adding defensive error handling would improve robustness:

     if (mimeType == null) {
       final mimeString = _resolver.lookup('', headerBytes: body);
-      mimeType = mimeString == null ? null : MimeType.parse(mimeString);
+      if (mimeString != null) {
+        try {
+          mimeType = MimeType.parse(mimeString);
+        } on FormatException {
+          // Invalid MIME string from resolver, ignore and fall back
+          mimeType = null;
+        }
+      }
     }

Alternatively, if you're confident the mime package always returns valid strings, the current code is acceptable.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3dbfe36 and 54c99f6.

📒 Files selected for processing (4)
  • lib/src/body/body.dart (4 hunks)
  • lib/src/body/types/body_type.dart (0 hunks)
  • lib/src/body/types/mime_type.dart (3 hunks)
  • test/body/body_infer_mime_type_test.dart (1 hunks)
💤 Files with no reviewable changes (1)
  • lib/src/body/types/body_type.dart
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-22T07:34:15.403Z
Learnt from: CR
PR: serverpod/relic#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-22T07:34:15.403Z
Learning: Applies to {lib,example}/**/*.dart : Use Uint8List for request/response bodies; do not use List<int>

Applied to files:

  • lib/src/body/body.dart
🔇 Additional comments (7)
lib/src/body/types/mime_type.dart (3)

48-48: LGTM! Clear documentation.

The added doc comment appropriately documents the constructor's purpose.


61-62: LGTM! Defensive input sanitization.

Adding .trim() correctly handles whitespace in MIME type strings, improving robustness against malformed input.


71-71: LGTM! Clear documentation.

The doc comment accurately describes the getter's behavior.

test/body/body_infer_mime_type_test.dart (1)

87-157: LGTM! Comprehensive binary MIME type inference tests.

The tests correctly use standard file format signatures (PNG, JPEG, GIF, PDF) and properly verify inference, fallback behavior, explicit overrides, and empty data handling.

lib/src/body/body.dart (3)

3-6: LGTM! Necessary imports for inference logic.

The dart:math import supports the min() function in the prefix extraction logic, and package:mime/mime.dart provides the MimeTypeResolver for binary MIME type detection.


57-76: LGTM! Well-documented optional inference.

The factory correctly makes mimeType optional and provides clear documentation about the inference behavior and performance implications. The fallback to MimeType.plainText is a sensible default.


113-117: LGTM! Sufficient whitespace detection.

The helper correctly identifies common whitespace characters (space, tab, newline, carriage return), which is sufficient for typical HTTP body content.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds automatic MIME type inference to the Relic web server's Body class. Instead of defaulting to text/plain and application/octet-stream, the Body constructors now analyze the content to detect appropriate MIME types like JSON, HTML, XML, and various binary formats.

Key changes:

  • Automatic MIME type detection for string and binary content when not explicitly provided
  • Removal of predefined static body type constants in favor of dynamic creation
  • Enhanced MIME type parsing with input sanitization

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
lib/src/body/body.dart Added MIME inference logic for text and binary content with fallback defaults
lib/src/body/types/body_type.dart Removed static body type presets, requiring explicit creation
lib/src/body/types/mime_type.dart Enhanced MIME type parsing with trimming and added documentation
test/body/body_infer_mime_type_test.dart Comprehensive test suite covering MIME inference scenarios

…Body.fromData

Tests cover:
- HTML text data detection
- XML text data detection
- JSON text data detection
- Unknown text data fallback to text/plain
- PNG binary data detection
- JPEG binary data detection
- GIF binary data detection
- PDF binary data detection
- Unknown binary data fallback to application/octet-stream
- Explicit mimeType override
- Empty binary data handling
Copy link
Contributor

@SandPod SandPod left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with one comment to remove redundant comments.

@nielsenko nielsenko merged commit c19219f into serverpod:main Oct 9, 2025
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Suggestion: Make Body.fromString default to returning HTML documents

2 participants