Skip to content

Conversation

@yamcodes
Copy link
Contributor

@yamcodes yamcodes commented Mar 21, 2025

Description

  • Introduced MAX_PAGINATION_LIMIT environment variable to control pagination limits
  • Updated configuration schema to validate the new variable
  • Modified ArticleFeedQuerySchema to utilize MAX_PAGINATION_LIMIT for dynamic limit enforcement

Closes #138


PR Checklist

  • Read the Developer's Guide in CONTRIBUTING.md
  • Use a concise title to represent the changes introduced in this PR
  • Provide a detailed description of the changes introduced in this PR, and, if necessary, some screenshots
  • Reference an issue or discussion where the feature or changes have been previously discussed
  • Add a failing test that passes with the changes introduced in this PR, or explain why it's not feasible
  • Add documentation for the feature or changes introduced in this PR to the docs; you can run them with bun docs

Summary by CodeRabbit

  • New Features
    • Improved article feed pagination by enforcing a maximum limit on the number of articles returned per request, enhancing query validation and ensuring consistent performance.
  • Chores
    • Updated the configuration example for improved clarity.

- Introduced MAX_PAGINATION_LIMIT environment variable to control pagination limits.
- Updated configuration schema to validate the new variable.
- Modified ArticleFeedQuerySchema to utilize MAX_PAGINATION_LIMIT for dynamic limit enforcement.
@yamcodes yamcodes linked an issue Mar 21, 2025 that may be closed by this pull request
4 tasks
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 21, 2025

Walkthrough

This pull request adds a new constant, MAX_PAGINATION_LIMIT, set to 1000 in the constants file. The ArticleFeedQuerySchema in the articles module now imports and uses this constant to enforce an upper bound on the limit property. Additionally, a trailing blank line was added to the environment example file.

Changes

File(s) Change Summary
src/articles/...schema.ts
src/constants.ts
Added a new constant MAX_PAGINATION_LIMIT (set to 1000) and updated the limit property in ArticleFeedQuerySchema to enforce a maximum value constraint.
.env.example A trailing blank line was appended.

Assessment against linked issues

Objective Addressed Explanation
Enforce maximum limit on limit query parameter (#138)

Poem

I'm a rabbit with a spring in my hop,
Boundaries now keep our queries from a flop.
Constants set the pace, precise and neat,
Limiting the numbers with a rhythmic beat.
Hoppy code and safe hops make my heart skip a beat!


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 52219bb and 502e221.

📒 Files selected for processing (3)
  • .env.example (1 hunks)
  • src/articles/articles.schema.ts (2 hunks)
  • src/constants.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .env.example
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/articles/articles.schema.ts
🔇 Additional comments (2)
src/constants.ts (2)

1-6: Good addition with clear documentation.

The constant is well-documented with a clear explanation of its purpose and the rationale behind the chosen value. The naming convention follows best practices for constants.

Based on the PR comments discussion, you considered making this an environment variable rather than a hardcoded constant. While the current implementation as a constant is clean and straightforward, you might consider making it configurable via environment variables in the future if the need arises for different limits across environments.


7-7: Proper file formatting.

Including a trailing blank line at the end of the file follows good coding practices.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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 (2)
src/config.ts (1)

17-17: Remove debugging console.log statement.

This console.log statement appears to be for debugging purposes and should be removed before merging.

-console.log(env.MAX_PAGINATION_LIMIT, typeof env.MAX_PAGINATION_LIMIT);
src/articles/articles.schema.ts (1)

78-80: Consider adding type validation for MAX_PAGINATION_LIMIT.

Since env.MAX_PAGINATION_LIMIT is a string being converted to a number, there's a small risk of runtime issues if the environment variable contains a non-numeric value.

Consider updating the env schema in config.ts to validate it's a numeric string:

-  MAX_PAGINATION_LIMIT: Type.String(),
+  MAX_PAGINATION_LIMIT: Type.String({ pattern: '^[0-9]+$' }),

Or alternatively, add a validation check after loading the environment:

// In config.ts
if (isNaN(Number(env.MAX_PAGINATION_LIMIT))) {
  throw new Error('MAX_PAGINATION_LIMIT must be a valid number');
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ddb69b and 2d2a66d.

📒 Files selected for processing (3)
  • .env (1 hunks)
  • src/articles/articles.schema.ts (2 hunks)
  • src/config.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
src/articles/articles.schema.ts (1)
src/config.ts (1) (1)
  • env (16-16)
🔇 Additional comments (4)
.env (1)

9-9: LGTM: MAX_PAGINATION_LIMIT environment variable added.

The new environment variable is correctly defined with a reasonable default value of 1000.

src/config.ts (1)

12-12: LGTM: MAX_PAGINATION_LIMIT added to environment schema.

The new environment variable is correctly added to the configuration schema.

src/articles/articles.schema.ts (2)

1-1: LGTM: Import env from config module.

The environment configuration is correctly imported to access the MAX_PAGINATION_LIMIT value.


78-80: LGTM: Pagination limit is now constrained by MAX_PAGINATION_LIMIT.

The ArticleFeedQuerySchema now properly uses the configured maximum pagination limit. Converting the string to a number is appropriate here.

@yamcodes
Copy link
Contributor Author

yamcodes commented Mar 21, 2025

@Hajbo I tried to make the env var optional with default (1000) but it didn't work.
When I set it to optional+default the resulting type is optional, which isn't what you'd expect (if there's a default value the resulting type should be guaranteed).
When I set it to just optional, there is no default value through the config and I really don't want to default it in the code itself, that's ugly.
When I set it to just default (but not optional), the config validation fails when the env isn't provided.

Maybe there's a great TypeBox way to solve it but I really rather work with something I know better like ark.env or Zod.

So this is kind of a quick fix where the env is forced. Let me know if that's annoying and we can hardcode it to 1000.

Accepting an attempt from @coderabbitai to make optional+default work despite my experience above ^

yamcodes and others added 3 commits March 21, 2025 18:38
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 21, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

I'll look into making the MAX_PAGINATION_LIMIT env variable optional with a default value using TypeBox. Let me first check the current configuration implementation.


🏁 Script executed:

#!/bin/bash
# First, let's examine the config.ts file to understand the current TypeBox usage
cat src/config.ts

# Then, check the related schema where this limit is used
cat src/articles/articles.schema.ts

# Let's also check if there are any examples of optional variables with defaults in the codebase
grep -r "Type.Optional" --include="*.ts" .

Length of output: 4027


Let me investigate TypeBox's handling of optional values with defaults. I'll first check if there's any documentation or examples on TypeBox's GitHub repository.


🏁 Script executed:

#!/bin/bash
# Let's check if any environment variables are set as optional anywhere in the codebase
grep -r "Type\.Optional.*Type\.String" --include="*.ts" .

# Let's check how defaults are handled in other parts of the codebase
grep -r "default:" --include="*.ts" .

# Let's also check for any examples of TypeBox usage with defaults in the codebase
grep -r "Type\.Default" --include="*.ts" .

Length of output: 523


I'll investigate TypeBox further to understand how to properly implement optional environment variables with defaults. Let me look at the TypeBox documentation and check for any examples of working with environment variables in the codebase.


🌐 Web query:

TypeBox Type.Default vs Type.Optional best practices

💡 Result:

TypeBox's Type.Optional and Type.Default serve distinct purposes in schema design:

Type.Optional

Used to indicate a property may be omitted or explicitly set to undefined, compatible with TypeScript's optional modifier (?).

Key Behaviors:

  • Generates a JSON Schema with "required": false
  • Requires enabling TypeSystemPolicy.ExactOptionalPropertyTypes (and exactOptionalPropertyTypes in tsconfig.json) to disallow undefined assignments while permitting omission[1]
  • Common in API schemas for optional query parameters/fields (e.g., avatar: Type.Optional(Type.String()) in Feathers.js[3], ElysiaJS routes[2])

Example:

const Schema = Type.Object({
  name: Type.Optional(Type.String())
});

// Valid: { }, { name: "Alice" }
// Invalid with ExactOptionalPropertyTypes: { name: undefined }

Type.Default

Used to set a default value when a property is missing, without affecting the underlying schema's required status.

Key Behaviors:

  • Does not modify the schema's required array
  • Useful for initializing missing values during runtime parsing/validation
  • Often combined with Type.Optional for explicit default assignments

Example:

const Schema = Type.Object({
  pageSize: Type.Default(Type.Number(), 10)
});

// If input lacks pageSize, Value.Cast(Schema, { }) → { pageSize: 10 }

When to Use Each

Use Case Type.Optional Type.Default
Truly optional field
Runtime default value
Input omission
Output initialization

Best Practices:

  1. Use Type.Optional for API contracts where clients may omit fields[2][3][4]
  2. Use Type.Default when you need to guarantee a value exists post-validation
  3. Enable exactOptionalPropertyTypes in both TypeBox and TypeScript for strict undefined handling[1]
  4. Avoid mixing them unless explicitly handling default initialization

For schemas requiring both omission semantics and default initialization, combine the two:

const Schema = Type.Object({
  active: Type.Optional(Type.Default(Type.Boolean(), false))
});

// Input { } → Value.Cast → { active: false }

Citations:


@yamcodes I've found a solution that should work for making MAX_PAGINATION_LIMIT optional with a default value. Based on TypeBox documentation, here's what you can do:

// In config.ts
const envSchema = Type.Object({
  // Other env variables...
  MAX_PAGINATION_LIMIT: Type.Optional(Type.String()),
});

if (!Value.Check(envSchema, Bun.env)) throw new Error('Invalid env variables');
export const env = Value.Cast(envSchema, Bun.env);

// Add this after the Value.Cast to guarantee the value exists
if (env.MAX_PAGINATION_LIMIT === undefined) {
  env.MAX_PAGINATION_LIMIT = "1000";
}

This approach:

  1. Makes the env var optional in the schema (passes validation if missing)
  2. Explicitly sets the default after validation
  3. Guarantees the value exists in the resulting object

TypeBox's Type.Default doesn't modify the schema's required status, which is why the optional+default approach wasn't working as expected. This solution separates the schema validation from the default value application.

- Updated MAX_PAGINATION_LIMIT in the environment schema to be a required string instead of an optional string with a default value.
- This change ensures stricter validation of the pagination limit configuration.
@yamcodes
Copy link
Contributor Author

yamcodes commented Mar 21, 2025

No offense @coderabbitai but that's ugly. No, thanks.

Also @Hajbo not really a fan of having the env config of this var be a "String" but to coalesce it to a number we probably need to use a dedicated env solution.

I'm biased cause I made ark.env but we can also use T3 Env which supports standard schema and looks interesting.

Just throwing it out there so we can tackle it once we finish the roadmap - it's really off topic here but just giving you context so you can help me decide what to do with this PR, now.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 21, 2025

Tip

For best results, initiate chat on the files or code changes.

@yamcodes No worries! I understand your concerns about the implementation style. For the current PR, you have a few practical options:

  1. Keep your current implementation if it's working for your immediate needs
  2. Hardcode the value to 1000 as you suggested earlier (simplest approach)
  3. Make the variable required without a default to enforce its presence

Regarding the type issues (String vs Number), that's a valid point that dedicated env solutions like ark.env or T3 Env would handle more elegantly. Those would definitely be worth exploring after completing your roadmap.

What would you prefer to do with this PR now? If you're looking for minimal changes, option 2 (hardcoding to 1000) might be the most straightforward for now.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 21, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@yamcodes I completely understand your concerns about the TypeBox implementation. After reviewing your code, here are the most straightforward options for this PR:

  1. Hardcode the value to 1000 directly in the schema - This eliminates the env variable entirely but gives you the functionality you need right now:

    // In articles.schema.ts
    const MAX_PAGINATION_LIMIT = 1000; // Hardcoded for now
    
    // Then use it directly
    limit: Type.Number({ minimum: 1, maximum: MAX_PAGINATION_LIMIT, default: 20 })
  2. Keep your current implementation - It works functionally even if the typing isn't ideal

The hardcoded approach is clean and simple until you have bandwidth to implement a proper env solution like ark.env or T3 Env after completing your roadmap.

What would you prefer to do with this PR?

(\ /)
(•ᴗ•)
/ >🧠 Thinking about better env typing solutions for the future...


🏁 Script executed:

#!/bin/bash
# Let's examine the current state of the files involved in this PR
echo "Checking config.ts for environment variable implementation:"
cat src/config.ts

echo -e "\nChecking articles.schema.ts for how it's being used:"
cat src/articles/articles.schema.ts

echo -e "\nChecking .env file for default values:"
cat .env || echo "No .env file found or can't access it"

Length of output: 4009


@yamcodes Looking at your current implementation, I see the MAX_PAGINATION_LIMIT is now defined as a required string without a default. Let me check the exact changes in this PR to give you better advice on how to proceed.


🏁 Script executed:

#!/bin/bash
# Let's see the actual diff changes in this PR
echo "Checking git diff for the changes in this PR:"
git diff HEAD^ HEAD -- src/config.ts src/articles/articles.schema.ts .env

Length of output: 206


@yamcodes It seems I'm having trouble accessing the exact diff. Let me try a different approach to understand what changes are being made in this PR so I can give you proper advice.


🏁 Script executed:

#!/bin/bash
# Let's try to see the changes using other git commands
echo "Checking git log to understand the history:"
git log --oneline -n 3

echo -e "\nChecking git status:"
git status

echo -e "\nLet's try using the files command to get all tracked files:"
git ls-files | grep -E 'config\.ts|articles\.schema\.ts|\.env'

echo -e "\nTrying to examine the actual PR using GitHub CLI:"
gh pr view 143 --json files

Length of output: 766


@yamcodes Let me examine what changes you've made to these files so I can better understand the current implementation and provide appropriate advice.


🏁 Script executed:

#!/bin/bash
# Let's examine the .env.example file to see what was added
echo "Examining .env.example for additions:"
cat .env.example

# Let's try to get the changes in articles.schema.ts and config.ts
echo -e "\nChecking the contents of src/articles/articles.schema.ts:"
cat src/articles/articles.schema.ts | grep -A 5 -B 5 MAX_PAGINATION_LIMIT

echo -e "\nChecking the contents of src/config.ts:"
cat src/config.ts | grep -A 3 -B 3 MAX_PAGINATION_LIMIT

# Let's also check if there's a .env.example file to see default values
echo -e "\nChecking if there's a PR branch we can compare with:"
git branch -a

Length of output: 1414


@yamcodes Based on the files I've examined, I now have a clear picture of what you're working with. Given your concerns about:

  1. The string-to-number conversion issue
  2. The lack of proper typing with TypeBox
  3. The need for a dedicated env solution in the future

Here's my recommendation for this PR:

Hardcode the value for now:

  1. In src/config.ts:

    • Remove the MAX_PAGINATION_LIMIT from the envSchema
  2. In src/articles/articles.schema.ts:

    • Add a constant at the top of the file:
      // TODO: Replace with proper env variable using a dedicated solution in the future
      const MAX_PAGINATION_LIMIT = 1000;
    • Update the schema to use this constant directly:
      limit: Type.Optional(
        Type.Number({
          minimum: 1,
          maximum: MAX_PAGINATION_LIMIT,
          default: 20,
        }),
      ),
  3. Keep the entry in .env.example for documentation purposes

This approach:

  • Eliminates the immediate typing issues
  • Provides a clean solution for now
  • Sets you up for a future implementation with ark.env or T3 Env after completing your roadmap

Would this approach work for your current needs?

(\ /)
(•ᴗ•)
/ >📝 Thinking pragmatically...


✏️ Learnings added
Learnt from: yamcodes
URL: https://github.com/agnyz/bedstack/pull/143

Timestamp: 2025-03-21T13:57:09.420Z
Learning: yamcodes is the creator of ark.env, which is a TypeScript env solution he would prefer over TypeBox for environment variable validation and typing.

Learnt from: yamcodes
URL: https://github.com/agnyz/bedstack/pull/143

Timestamp: 2025-03-21T13:57:09.420Z
Learning: yamcodes prefers not to have environment variables typed as strings that need to be coalesced to numbers in the codebase. A dedicated env solution would be preferred for proper typing.

Learnt from: yamcodes
URL: https://github.com/agnyz/bedstack/pull/143

Timestamp: 2025-03-21T13:57:09.420Z
Learning: For environment variables that need type conversion (like string to number), yamcodes prefers dedicated environment variable solutions like ark.env (which he created) or T3 Env that handle typing properly, rather than using TypeBox's string validation with manual type conversion.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@yamcodes yamcodes changed the title feat: Add MAX_PAGINATION_LIMIT to configuration Add MAX_PAGINATION_LIMIT Mar 21, 2025
@yamcodes yamcodes changed the title Add MAX_PAGINATION_LIMIT Add MAX_PAGINATION_LIMIT Mar 21, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 21, 2025

Tip

For best results, initiate chat on the files or code changes.

@yamcodes I understand your frustration with TypeBox's handling of environment variables. For this immediate PR, the hardcoded approach you mentioned seems most practical:

// In src/articles/articles.schema.ts
// TODO: Replace with proper env variable using a dedicated solution in the future
const MAX_PAGINATION_LIMIT = 1000;

// Then in your schema:
limit: Type.Number({ 
  minimum: 1, 
  maximum: MAX_PAGINATION_LIMIT, 
  default: 20 
}),

This gives you a clean solution now while setting the stage for proper implementation with ark.env or T3 Env after completing your roadmap. You can remove the MAX_PAGINATION_LIMIT from the envSchema in config.ts but might want to keep it in .env.example for documentation.


✏️ Learnings added
Learnt from: yamcodes
URL: https://github.com/agnyz/bedstack/pull/143

Timestamp: 2025-03-21T13:58:14.074Z
Learning: yamcodes is the creator of ark.env, which is a TypeScript env solution he would prefer over TypeBox for environment variable validation and typing.

Learnt from: yamcodes
URL: https://github.com/agnyz/bedstack/pull/143

Timestamp: 2025-03-21T13:58:14.074Z
Learning: yamcodes prefers not to have environment variables typed as strings that need to be coalesced to numbers in the codebase. A dedicated env solution would be preferred for proper typing.

Learnt from: yamcodes
URL: https://github.com/agnyz/bedstack/pull/143

Timestamp: 2025-03-21T13:58:14.074Z
Learning: For environment variables that need type conversion (like string to number), yamcodes prefers dedicated environment variable solutions like ark.env (which he created) or T3 Env that handle typing properly, rather than using TypeBox's string validation with manual type conversion.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 21, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@yamcodes I've looked at the current implementation and understand the challenge with TypeBox. Here's a solution that should work while keeping the codebase clean:

In src/config.ts:

// Make it optional, but no default in the schema definition
MAX_PAGINATION_LIMIT: Type.Optional(Type.String()),

// Then after validation, add this code:
if (!Value.Check(envSchema, Bun.env)) {
  throw new Error('Invalid env variables');
}

export const env = Value.Cast(envSchema, Bun.env);

// Add this line to set the default after validation
if (env.MAX_PAGINATION_LIMIT === undefined) {
  env.MAX_PAGINATION_LIMIT = '1000';
}

This approach:

  1. Makes the env var truly optional in the schema validation
  2. Explicitly sets the default after validation
  3. Ensures the variable always exists in the env object
  4. Keeps the configuration in one place

Alternatively, if you'd prefer to hardcode it to 1000 as mentioned, you could remove it from env variables entirely and define it as a constant in articles.schema.ts:

// In articles.schema.ts
const MAX_PAGINATION_LIMIT = 1000;

// Use directly in the schema
limit: Type.Number({
  minimum: 1,
  maximum: MAX_PAGINATION_LIMIT,
  default: 20,
}),

Let me know which approach you prefer!


🏁 Script executed:

#!/bin/bash
# Let's examine the config.ts file to understand how TypeBox is used for env variables
cat src/config.ts

# Let's check the articles schema to see how MAX_PAGINATION_LIMIT is being used
cat src/articles/articles.schema.ts

# Let's also check if there's a .env.example file
cat .env.example 2>/dev/null || echo ".env.example not found"

Length of output: 3742


🏁 Script executed:

#!/bin/bash
# Let's specifically check how MAX_PAGINATION_LIMIT is defined in config.ts
grep -A 3 -B 3 "MAX_PAGINATION_LIMIT" src/config.ts

# Let's also check how it's used in the articles schema
grep -A 3 -B 3 "MAX_PAGINATION_LIMIT" src/articles/articles.schema.ts

# Let's see how other environment variables are defined for comparison
grep "Type.Optional" src/config.ts
grep "default:" src/config.ts

Length of output: 595


@yamcodes I understand your frustration with TypeBox's handling of optional variables with defaults. After examining your code, I can see the issue clearly.

Looking at your current implementation:

// In config.ts
MAX_PAGINATION_LIMIT: Type.String(),

// In articles.schema.ts
maximum: Number(env.MAX_PAGINATION_LIMIT)

You're right that TypeBox doesn't handle optional+default in an intuitive way. Based on your preferences and the constraints, here are two simple options:

Option 1: Post-validation default (cleanest TypeBox approach)

// In config.ts - make it optional
MAX_PAGINATION_LIMIT: Type.Optional(Type.String()),

// Then after validation:
export const env = Value.Cast(envSchema, Bun.env);

// Set default after validation
if (env.MAX_PAGINATION_LIMIT === undefined) {
  env.MAX_PAGINATION_LIMIT = '1000';
}

Option 2: Hardcode to 1000 (simplest approach)

// In articles.schema.ts
// Remove the env import if it's only used for MAX_PAGINATION_LIMIT
const MAX_PAGINATION_LIMIT = 1000; // Hardcoded for now

// Then in the schema
maximum: MAX_PAGINATION_LIMIT,

Since you mentioned you'd be open to hardcoding it to 1000, option 2 might be the quickest solution for now, especially if you plan to revisit with ark.env or T3 Env later.

Which approach would you prefer?


✏️ Learnings added
Learnt from: yamcodes
URL: https://github.com/agnyz/bedstack/pull/143

Timestamp: 2025-03-21T13:59:02.022Z
Learning: TypeBox's Type.Optional with default values results in an optional type, even though the default value is applied during validation. This doesn't guarantee the value exists in the resulting type.

Learnt from: yamcodes
URL: https://github.com/agnyz/bedstack/pull/143

Timestamp: 2025-03-21T13:59:02.022Z
Learning: For environment variables requiring default values in TypeBox, a post-validation step can be used to set defaults after Value.Cast/Check, ensuring the values exist while keeping the schema validation intact.

Learnt from: yamcodes
URL: https://github.com/agnyz/bedstack/pull/143

Timestamp: 2025-03-21T13:59:02.022Z
Learning: TypeBox's behavior with optional + default values is unintuitive - when setting a property as Type.Optional(Type.String({ default: '1000' })), the resulting type is still optional even though it has a default value.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@yamcodes yamcodes self-assigned this Mar 21, 2025
@Hajbo
Copy link
Collaborator

Hajbo commented Mar 22, 2025

@Hajbo I tried to make the env var optional with default (1000) but it didn't work. When I set it to optional+default the resulting type is optional, which isn't what you'd expect (if there's a default value the resulting type should be guaranteed). When I set it to just optional, there is no default value through the config and I really don't want to default it in the code itself, that's ugly. When I set it to just default (but not optional), the config validation fails when the env isn't provided.

Maybe there's a great TypeBox way to solve it but I really rather work with something I know better like ark.env or Zod.

So this is kind of a quick fix where the env is forced. Let me know if that's annoying and we can hardcode it to 1000.

Accepting an attempt from @coderabbitai to make optional+default work despite my experience above ^

I'm not even sure if an env var is the way do to it. To me an env var is a runtime variable that is either sensitive (database credentials), or needs to be changed easily without changing the code itself (environment name, external service urls). An upper bound for pagination sounds like a simple constant to me, if I changed it, I probably want to deploy a new version of the code.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 22, 2025

Tip

For best results, initiate chat on the files or code changes.

@Hajbo You make an excellent point about environment variables vs. constants. I completely agree that environment variables are best suited for:

  1. Sensitive information like credentials
  2. Values that vary between environments
  3. Configuration that needs to change without code deployment

A pagination limit doesn't really fit these criteria - it's an application-level constraint that would typically change alongside code changes with proper testing. This makes it a great candidate for a simple constant.

The easiest solution would be:

// In src/articles/articles.schema.ts
const MAX_PAGINATION_LIMIT = 1000;

// Then in your schema
limit: Type.Number({ 
  minimum: 1, 
  maximum: MAX_PAGINATION_LIMIT, 
  default: 20 
}),

This approach is clean, type-safe, and removes all the complexity of dealing with TypeBox's environment variable handling.


✏️ Learnings added
Learnt from: Hajbo
URL: https://github.com/agnyz/bedstack/pull/143

Timestamp: 2025-03-22T04:23:47.521Z
Learning: For application constraints like pagination limits that don't vary between environments and aren't sensitive, using code constants is preferred over environment variables in the bedstack codebase.

Learnt from: Hajbo
URL: https://github.com/agnyz/bedstack/pull/143

Timestamp: 2025-03-22T04:23:47.521Z
Learning: When a configuration value would typically require testing and a new deployment when changed (like pagination limits), it's better implemented as a code constant rather than an environment variable in the bedstack project.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@yamcodes yamcodes requested a review from Hajbo March 22, 2025 06:23
@yamcodes yamcodes merged commit 0df91cc into main Mar 22, 2025
4 checks passed
@yamcodes yamcodes deleted the 138-limit-does-not-have-an-upper-bound branch March 22, 2025 06:49
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.

Limit does not have an upper bound

3 participants