Skip to content

Comments

Added documentation#54

Merged
rkritika1508 merged 9 commits intomainfrom
feat/documentation
Feb 19, 2026
Merged

Added documentation#54
rkritika1508 merged 9 commits intomainfrom
feat/documentation

Conversation

@rkritika1508
Copy link
Collaborator

@rkritika1508 rkritika1508 commented Feb 17, 2026

Summary

Target issue is #55.
Explain the motivation for making this change. What existing problem does the pull request solve?
Added documentation for the following -

  1. API documentation (OpenAPI/Swagger)
  2. README with setup instructions, development and deployment mds
  3. API usage guide
  4. Validator configuration guide

Checklist

Before submitting a pull request, please ensure that you mark these task.

  • Ran fastapi run --reload app/main.py or docker compose up in the repository root and test.
  • If you've fixed a bug or added code that is tested and has test cases.

Notes

Please add here if any other information is required for the reviewer.

Summary by CodeRabbit

  • Documentation

    • Enhanced API usage guide with comprehensive endpoint documentation and examples
    • Expanded validator configuration guidance and supported validator types
    • Added detailed ban list management documentation
    • Updated development and deployment instructions with corrected port mappings
    • Clarified database initialization and Docker setup procedures
  • New Features

    • API responses now include structured error and metadata fields for better error handling

@coderabbitai
Copy link

coderabbitai bot commented Feb 17, 2026

Warning

Rate limit exceeded

@rkritika1508 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 21 minutes and 17 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/documentation

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.

@rkritika1508 rkritika1508 marked this pull request as ready for review February 18, 2026 11:21
Copy link

@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: 1

🧹 Nitpick comments (8)
development.md (1)

13-13: Minor grammar: use hyphen in compound adjective.

"JSON based" should be "JSON-based" when used as a compound adjective before a noun.

📝 Proposed fix
-Backend, JSON based web API based on OpenAPI: <http://localhost:8001>
+Backend, JSON-based web API based on OpenAPI: <http://localhost:8001>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@development.md` at line 13, Replace the compound adjective "JSON based" with
the hyphenated form "JSON-based" in the documentation string ("Backend, JSON
based web API based on OpenAPI: <http://localhost:8001>") so it reads "Backend,
JSON-based web API based on OpenAPI: <http://localhost:8001>" to correct the
grammar.
backend/README.md (1)

267-281: Add language specifier to fenced code block.

The code block should specify a language for proper syntax highlighting in documentation renderers.

📝 Proposed fix
-```
+```python
 from guardrails.hub import # validator name from Guardrails Hub

Apply the same fix to the code block at line 339.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/README.md` around lines 267 - 281, The fenced code block showing the
new validator file example is missing a language specifier; update the
triple-backtick fence to ```python for the block that begins with "from
guardrails.hub import" and the block at the later example (line ~339) so both
code blocks start with ```python to enable proper syntax highlighting; no other
code changes needed—just change the opening fences to ```python around the
examples that include the class <Validator-name>SafetyValidatorConfig and its
import line.
backend/app/core/validators/README.md (1)

41-43: Heading hierarchy inconsistency.

Line 41 uses ## Validator Details but line 43 uses ## 1) Lexical Slur Validator... at the same level. The individual validator sections should be subheadings (###) under "Validator Details" for proper hierarchy.

📝 Proposed fix for heading hierarchy
 ## Validator Details
 
-## 1) Lexical Slur Validator (`uli_slur_match`)
+### 1) Lexical Slur Validator (`uli_slur_match`)

Apply the same change to lines 81, 122, and 159 for validators 2, 3, and 4.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/core/validators/README.md` around lines 41 - 43, Change the
individual validator headings under the top-level "Validator Details" from
level-2 to level-3 so they become subsections; specifically update the "1)
Lexical Slur Validator (`uli_slur_match`)" heading and do the same for the other
validator headings (validators 2, 3, and 4) so each uses ### instead of ## to be
proper children of "Validator Details".
backend/app/api/docs/ban_lists/list_ban_lists.md (1)

14-15: Consider documenting the default value for limit.

The offset parameter documents its default value (0), but limit only specifies min/max constraints without a default. For consistency and clarity, consider adding the default value if one exists.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/api/docs/ban_lists/list_ban_lists.md` around lines 14 - 15, The
documentation for the list ban lists endpoint omits the default for the `limit`
parameter while `offset` has `default: 0`; add the `default` value for `limit`
(e.g., `default: 20` or whatever the implementation uses) in the `limit`
parameter line so it reads like the `offset` line, updating the `limit` entry in
list_ban_lists.md to include `default: <value>` next to the existing `min`/`max`
constraints.
backend/app/api/docs/guardrails/list_validators.md (1)

15-23: Response format differs from other endpoints.

This endpoint returns a plain object {"validators": [...]} (per the code in guardrails.py line 85) rather than the APIResponse wrapper used by other endpoints. The documentation accurately reflects this, but consider whether this inconsistency is intentional. Other guardrail endpoints use APIResponse[...] for both success and failure responses.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/api/docs/guardrails/list_validators.md` around lines 15 - 23, The
endpoint implemented in guardrails.py (function/handler list_validators) returns
a plain object {"validators": [...]} while other guardrail endpoints return an
APIResponse[...] wrapper; make them consistent by updating list_validators to
return an APIResponse success payload containing the validators (e.g.,
APIResponse[data={"validators": [...]}]) and ensure error paths return
APIResponse failure as well, or if you intentionally prefer the plain object,
update the docs to state the deviation; locate the response construction in
guardrails.py (around the current return that builds the validators list) and
adjust the return shape to use the same APIResponse wrapper used by other
endpoints and mirror their success/error formatting.
backend/app/utils.py (2)

70-76: Consider defensive handling for malformed error list items.

If error is a list but contains items without get method (non-dict items), this will raise an AttributeError. Consider adding type checking or using a safer access pattern.

🛡️ Proposed defensive handling
         if isinstance(error, list):  # to handle cases when error is a list of errors
             error_message = "\n".join(
                 [
-                    f"{err.get('loc', 'unknown')}: {err.get('msg', str(err))}"
+                    f"{err.get('loc', 'unknown')}: {err.get('msg', str(err))}" 
+                    if isinstance(err, dict) else str(err)
                     for err in error
                 ]
             )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/utils.py` around lines 70 - 76, The list-joining logic assumes
each item in error supports .get and will raise AttributeError for non-dict
items; update the handling in the block that builds error_message (the code that
checks isinstance(error, list)) to defensively process each item: if an item is
a dict use item.get('loc','unknown') and item.get('msg', str(item)), otherwise
treat the item as a scalar/exception and use its string representation for both
location (e.g., 'unknown') and message; ensure the resulting error_message uses
these safe fallbacks so malformed list entries cannot crash the function.

37-48: Clarify the file existence check logic.

The exists() check on line 39 tests if the path exists relative to the current working directory. For typical usage like load_description("ban_lists/create_ban_list.md"), this will almost always fail, falling through to the api/docs fallback. This works but is conceptually backwards—the fallback is actually the primary path.

Consider inverting the logic for clarity:

♻️ Proposed refactor for clearer intent
 `@ft.singledispatch`
 def load_description(filename: Path) -> str:
-    if not filename.exists():
-        this = Path(__file__)
-        filename = this.parent.joinpath("api", "docs", filename)
-
-    return filename.read_text()
+    # Primary path: relative to api/docs directory
+    docs_path = Path(__file__).parent.joinpath("api", "docs", filename)
+    if docs_path.exists():
+        return docs_path.read_text()
+    # Fallback: treat as absolute or CWD-relative path
+    return filename.read_text()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/utils.py` around lines 37 - 48, The existence check is inverted:
currently you test the raw filename first and then fall back to api/docs, which
makes api/docs the de facto primary; update load_description (the Path-handling
implementation registered with `@ft.singledispatch`) to first construct
this.parent.joinpath("api","docs", filename) and use that path if it exists,
otherwise fall back to the original filename; keep the string overload
_(filename: str) -> str calling load_description(Path(filename)) unchanged and
ensure filename resolution uses Path objects consistently before calling
read_text().
backend/app/api/API_USAGE.md (1)

352-361: Consider keeping validator types in sync with code.

The hardcoded list of validator types should be kept in sync with validators.json. Consider adding a note about where the source of truth lives or automating this documentation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/api/API_USAGE.md` around lines 352 - 361, Update the "Current
Validator Types" section so it does not hardcode a potentially stale list:
replace the manual list under the "Current Validator Types" heading with a clear
statement that the canonical source is validators.json and link to
backend/app/core/validators/README.md; alternatively add instructions to
generate this list from validators.json (e.g., a small script or CI step named
something like generate-validator-docs or validate-docs) and mention that the CI
check ensures API_USAGE.md stays in sync. Ensure references to
'validators.json', the "Current Validator Types" section, and
'backend/app/core/validators/README.md' are included so future authors know the
source of truth and how to automate updates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/README.md`:
- Line 371: Update the README step numbering to fix the duplicate "2." entries:
in the "Adding a new validator from Guardrails Hub" section ensure the sequence
reads "1., 2., 3." and in the "How to add custom validators?" section renumber
the second "2." to "3."; this is a documentation-only change referenced to the
README content and also ensure the instruction that mentions adding the new
config class to ValidatorConfigItem (in backend/app/schemas/guardrail_config.py)
remains under the correctly numbered step.

---

Duplicate comments:
In `@backend/app/api/routes/guardrails.py`:
- Line 58: The description argument is passing a plain string to
load_description where a Path is expected; update the call in the router.get
decorator to pass a pathlib.Path object (e.g., wrap
"guardrails/list_validators.md" with Path(...)) and add the necessary import for
Path from pathlib at top of the file so router.get and load_description receive
the correct type.

---

Nitpick comments:
In `@backend/app/api/API_USAGE.md`:
- Around line 352-361: Update the "Current Validator Types" section so it does
not hardcode a potentially stale list: replace the manual list under the
"Current Validator Types" heading with a clear statement that the canonical
source is validators.json and link to backend/app/core/validators/README.md;
alternatively add instructions to generate this list from validators.json (e.g.,
a small script or CI step named something like generate-validator-docs or
validate-docs) and mention that the CI check ensures API_USAGE.md stays in sync.
Ensure references to 'validators.json', the "Current Validator Types" section,
and 'backend/app/core/validators/README.md' are included so future authors know
the source of truth and how to automate updates.

In `@backend/app/api/docs/ban_lists/list_ban_lists.md`:
- Around line 14-15: The documentation for the list ban lists endpoint omits the
default for the `limit` parameter while `offset` has `default: 0`; add the
`default` value for `limit` (e.g., `default: 20` or whatever the implementation
uses) in the `limit` parameter line so it reads like the `offset` line, updating
the `limit` entry in list_ban_lists.md to include `default: <value>` next to the
existing `min`/`max` constraints.

In `@backend/app/api/docs/guardrails/list_validators.md`:
- Around line 15-23: The endpoint implemented in guardrails.py (function/handler
list_validators) returns a plain object {"validators": [...]} while other
guardrail endpoints return an APIResponse[...] wrapper; make them consistent by
updating list_validators to return an APIResponse success payload containing the
validators (e.g., APIResponse[data={"validators": [...]}]) and ensure error
paths return APIResponse failure as well, or if you intentionally prefer the
plain object, update the docs to state the deviation; locate the response
construction in guardrails.py (around the current return that builds the
validators list) and adjust the return shape to use the same APIResponse wrapper
used by other endpoints and mirror their success/error formatting.

In `@backend/app/core/validators/README.md`:
- Around line 41-43: Change the individual validator headings under the
top-level "Validator Details" from level-2 to level-3 so they become
subsections; specifically update the "1) Lexical Slur Validator
(`uli_slur_match`)" heading and do the same for the other validator headings
(validators 2, 3, and 4) so each uses ### instead of ## to be proper children of
"Validator Details".

In `@backend/app/utils.py`:
- Around line 70-76: The list-joining logic assumes each item in error supports
.get and will raise AttributeError for non-dict items; update the handling in
the block that builds error_message (the code that checks isinstance(error,
list)) to defensively process each item: if an item is a dict use
item.get('loc','unknown') and item.get('msg', str(item)), otherwise treat the
item as a scalar/exception and use its string representation for both location
(e.g., 'unknown') and message; ensure the resulting error_message uses these
safe fallbacks so malformed list entries cannot crash the function.
- Around line 37-48: The existence check is inverted: currently you test the raw
filename first and then fall back to api/docs, which makes api/docs the de facto
primary; update load_description (the Path-handling implementation registered
with `@ft.singledispatch`) to first construct this.parent.joinpath("api","docs",
filename) and use that path if it exists, otherwise fall back to the original
filename; keep the string overload _(filename: str) -> str calling
load_description(Path(filename)) unchanged and ensure filename resolution uses
Path objects consistently before calling read_text().

In `@backend/README.md`:
- Around line 267-281: The fenced code block showing the new validator file
example is missing a language specifier; update the triple-backtick fence to
```python for the block that begins with "from guardrails.hub import" and the
block at the later example (line ~339) so both code blocks start with ```python
to enable proper syntax highlighting; no other code changes needed—just change
the opening fences to ```python around the examples that include the class
<Validator-name>SafetyValidatorConfig and its import line.

In `@development.md`:
- Line 13: Replace the compound adjective "JSON based" with the hyphenated form
"JSON-based" in the documentation string ("Backend, JSON based web API based on
OpenAPI: <http://localhost:8001>") so it reads "Backend, JSON-based web API
based on OpenAPI: <http://localhost:8001>" to correct the grammar.

@rkritika1508 rkritika1508 linked an issue Feb 18, 2026 that may be closed by this pull request
Copy link

@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.

🧹 Nitpick comments (5)
backend/app/utils.py (2)

37-48: Missing validation for fallback path existence.

If filename doesn't exist, the code constructs a fallback path but doesn't verify the fallback exists before calling read_text(). This can produce a confusing FileNotFoundError pointing to the fallback path rather than the original.

🛡️ Proposed improvement
 `@ft.singledispatch`
 def load_description(filename: Path) -> str:
     if not filename.exists():
         this = Path(__file__)
         filename = this.parent.joinpath("api", "docs", filename)
-
+        if not filename.exists():
+            raise FileNotFoundError(
+                f"Documentation file not found: {filename}"
+            )
     return filename.read_text()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/utils.py` around lines 37 - 48, The load_description function
currently falls back to this.parent.joinpath("api","docs", filename) without
verifying that fallback exists; update load_description (the singledispatch base
function and its str-registered wrapper) to check after constructing the
fallback Path that it.exists() and only then call read_text(); if neither the
original filename nor the constructed fallback exists, raise a FileNotFoundError
(or a clear exception) that includes the original requested filename and the
attempted fallback path so the error message is informative.

70-76: Error location formatting may produce unclear output.

Pydantic validation errors have loc as a tuple (e.g., ('body', 'field_name')), not a string. The current formatting would render as "('body', 'field_name'): message" rather than a readable path.

🔧 Proposed fix
         if isinstance(error, list):  # to handle cases when error is a list of errors
             error_message = "\n".join(
                 [
-                    f"{err.get('loc', 'unknown')}: {err.get('msg', str(err))}"
+                    f"{'.'.join(str(p) for p in err.get('loc', ('unknown',)))}: {err.get('msg', str(err))}"
                     for err in error
                 ]
             )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/utils.py` around lines 70 - 76, The current error-message builder
treats pydantic error "loc" tuples as raw strings, producing awkward output like
"('body','field'): msg"; update the logic that constructs error_message (the
list comprehension handling isinstance(error, list) in utils.py) to convert each
err.get('loc') tuple into a readable path (e.g., join tuple elements with '.' or
use indexed notation for ints) before formatting the final string; ensure you
still fall back to 'unknown' when loc is missing and keep the rest of the
message as err.get('msg', str(err)).
backend/app/core/validators/README.md (1)

41-43: Minor heading hierarchy inconsistency.

The validator detail sections (e.g., "## 1) Lexical Slur Validator") use ## but appear under "## Validator Details", creating ambiguous hierarchy. Consider using ### for the numbered validator subsections.

📝 Suggested fix
 ## Validator Details
 
-## 1) Lexical Slur Validator (`uli_slur_match`)
+### 1) Lexical Slur Validator (`uli_slur_match`)

Apply the same pattern to sections 2, 3, and 4.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/core/validators/README.md` around lines 41 - 43, Change the
numbered validator subsection headings under "## Validator Details" from level-2
to level-3 headings (i.e., replace "## 1) Lexical Slur Validator
(`uli_slur_match`)" and the equivalent headings for sections 2, 3, and 4 with
"### ...") so the hierarchy is clear and the subsections (e.g., "Lexical Slur
Validator (`uli_slur_match`)", and the other three validator headings) are
nested under the "Validator Details" section.
development.md (1)

13-13: Minor grammar fix: hyphenate compound adjective.

"JSON based" should be "JSON-based" when used as a compound adjective before a noun.

📝 Suggested fix
-Backend, JSON based web API based on OpenAPI: <http://localhost:8001>
+Backend, JSON-based web API based on OpenAPI: <http://localhost:8001>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@development.md` at line 13, Change the compound adjective "JSON based" to the
hyphenated form "JSON-based" in the text line containing "Backend, JSON based
web API based on OpenAPI: <http://localhost:8001>" so it reads "Backend,
JSON-based web API based on OpenAPI: <http://localhost:8001>" to correct the
grammar.
backend/app/api/docs/ban_lists/delete_ban_list.md (1)

19-22: Consider adding failure case for non-owner attempts.

The documentation mentions "Only owner scope is allowed to delete the resource" (line 3), but the failure cases don't explicitly list what happens when a non-owner attempts deletion. Adding this would improve completeness:

📝 Suggested addition
 ## Failure Behavior
 Common failure cases:
 - Missing or invalid `X-API-KEY`
 - Ban list not found for the tenant scope
+- Insufficient permissions (non-owner attempting delete)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/api/docs/ban_lists/delete_ban_list.md` around lines 19 - 22,
Update the "Failure Behavior" section in delete_ban_list.md to include the
non-owner deletion case by adding a bullet describing that requests from
authenticated tenants who are not the resource owner are rejected (e.g.,
"Requester is not the owner of the resource — returns 403 Forbidden"); ensure
the language matches existing bullets like "Missing or invalid `X-API-KEY`" and
references the documented owner-only restriction so readers know non-owner
attempts are an explicit failure mode.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@backend/README.md`:
- Line 371: In the "How to add custom validators?" section of the README update
the duplicate step number "2." to "3." so the steps are sequential; specifically
change the step that instructs adding the new config class to
ValidatorConfigItem to be numbered "3." and ensure subsequent steps (if any) are
renumbered accordingly to maintain proper ordering.

---

Nitpick comments:
In `@backend/app/api/docs/ban_lists/delete_ban_list.md`:
- Around line 19-22: Update the "Failure Behavior" section in delete_ban_list.md
to include the non-owner deletion case by adding a bullet describing that
requests from authenticated tenants who are not the resource owner are rejected
(e.g., "Requester is not the owner of the resource — returns 403 Forbidden");
ensure the language matches existing bullets like "Missing or invalid
`X-API-KEY`" and references the documented owner-only restriction so readers
know non-owner attempts are an explicit failure mode.

In `@backend/app/core/validators/README.md`:
- Around line 41-43: Change the numbered validator subsection headings under "##
Validator Details" from level-2 to level-3 headings (i.e., replace "## 1)
Lexical Slur Validator (`uli_slur_match`)" and the equivalent headings for
sections 2, 3, and 4 with "### ...") so the hierarchy is clear and the
subsections (e.g., "Lexical Slur Validator (`uli_slur_match`)", and the other
three validator headings) are nested under the "Validator Details" section.

In `@backend/app/utils.py`:
- Around line 37-48: The load_description function currently falls back to
this.parent.joinpath("api","docs", filename) without verifying that fallback
exists; update load_description (the singledispatch base function and its
str-registered wrapper) to check after constructing the fallback Path that
it.exists() and only then call read_text(); if neither the original filename nor
the constructed fallback exists, raise a FileNotFoundError (or a clear
exception) that includes the original requested filename and the attempted
fallback path so the error message is informative.
- Around line 70-76: The current error-message builder treats pydantic error
"loc" tuples as raw strings, producing awkward output like "('body','field'):
msg"; update the logic that constructs error_message (the list comprehension
handling isinstance(error, list) in utils.py) to convert each err.get('loc')
tuple into a readable path (e.g., join tuple elements with '.' or use indexed
notation for ints) before formatting the final string; ensure you still fall
back to 'unknown' when loc is missing and keep the rest of the message as
err.get('msg', str(err)).

In `@development.md`:
- Line 13: Change the compound adjective "JSON based" to the hyphenated form
"JSON-based" in the text line containing "Backend, JSON based web API based on
OpenAPI: <http://localhost:8001>" so it reads "Backend, JSON-based web API based
on OpenAPI: <http://localhost:8001>" to correct the grammar.

@rkritika1508 rkritika1508 merged commit 1d62fc2 into main Feb 19, 2026
1 check passed
@rkritika1508 rkritika1508 deleted the feat/documentation branch February 19, 2026 12:49
rkritika1508 added a commit that referenced this pull request Feb 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add documentation

2 participants