Introduction

In the previous lessons, you learned how to build a basic Django API for rolling dice and how to create a user-friendly landing page. Now, we will make your API more powerful and flexible by supporting dice notation and improving input validation.

Dice notation is a standard way to describe dice rolls, especially in games. By adding support for this notation, your API will be easier to use and more familiar to many users. We will also ensure that the API handles bad input gracefully, returning clear error messages when something goes wrong.

By the end of this lesson, you’ll be able to parse and validate dice notation like 2d6, d20, or 4d8+2, enforce sensible limits on dice rolls and modifiers, and return clear error messages for invalid input. You’ll also learn how to write tests to make sure your code works as expected.

Let’s get started!

What Is Dice Notation?

Dice notation is a shorthand way to describe rolling dice, often used in tabletop games. The most common format is:

Where:

  • N is the number of dice to roll (optional, defaults to 1)
  • M is the number of sides on each die
  • [+/-K] is an optional modifier to add to or subtract from the total

Here are some examples:

  • 2d6 means roll two six-sided dice and add the results.
  • d20 means roll one twenty-sided die.
  • 4d8+2 means roll four eight-sided dice and add 2 to the total.
  • 3d10-1 means roll three ten-sided dice and subtract 1 from the total.

This notation is popular because it is concise and easy to read. By supporting it in your API, you make it more convenient for users who are familiar with these conventions.

Why LLMs Excel at Standard Formats

Dice notation is a standard, well-established format used across many games and applications. This is important because LLM agents like Codex are usually very good at implementing standard formats and patterns. When you ask Codex to implement dice notation, it has likely seen countless examples of this pattern in its training data, so it can generate working code relatively easily.

This principle applies to many other standard formats: regular expressions, date/time formatting (ISO 8601, RFC 3339), JSON schemas, URL patterns, Markdown parsing, and CSV formatting. However, LLMs can hallucinate and produce incorrect output. Always review, test, and verify generated code—especially for critical functionality—before deploying to production.

Parsing And Validating Dice Notation

Let’s break down how to parse and validate dice notation step by step.

Step 1: Recognize the Pattern

First, you need to recognize the pattern of dice notation. You can use a regular expression to match strings like 2d6, d20, 4d8+2, or 3d10-1.

For example, you might use a pattern like this:

This pattern matches:

  • An optional number (the count of dice)
  • The letter d
  • The number of sides
  • An optional modifier (either + or - followed by a number)
Step 2: Extract Values

Once you have a match, extract the values:

  • If the count is missing (e.g., d20), default it to 1.
  • Parse the number of sides and the modifier (if present).

For example, parsing 4d8+2 gives:

  • count = 4
  • sides = 8
  • modifier = 2

Parsing d20 gives:

  • count = 1 (default)
  • sides = 20
  • modifier = 0 (default)
Step 3: Validate the Input

It’s important to enforce sensible limits to prevent abuse or errors. For example:

  • The number of dice (count) should be between 1 and 100.
  • The number of sides (sides) should be between 2 and 1,000.
  • The modifier (modifier) should be between -1,000 and 1,000.

If any value is out of range, you should return a clear error message.

Here’s how you might handle bad input:

This should return:

By validating input, you make your API safer and easier to use.

Updating The API Endpoint

Now, let’s update the /roll/ endpoint to support dice notation and improved validation.

Step 1: Prioritize "expr" Over "count"/"sides"

If the user provides an expr parameter (like 2d6+3), you should parse and use it. If not, fall back to the older count and sides parameters.

For example, if the request is:

You should parse 3d10-1 and use those values.

If the request is:

You should use count=2 and sides=6.

Step 2: Return Clear Error Messages

If the input is invalid, return a JSON error with HTTP status 400. For example:

Should return:

Step 3: Example Success Response

For a valid request like:

A possible response might be:

This shows the individual dice rolls, the total (including the modifier), and echoes back the parameters used.

Testing The Parser And Endpoint

Testing is important to make sure your code works and handles errors correctly.

Step 1: Test the Parser

Write unit tests for your dice notation parser. Test both valid and invalid cases.

For example:

Step 2: Test the Endpoint

Write tests for the /roll/ endpoint. Make sure to test:

  • Valid dice notation
  • Valid count/sides parameters
  • Invalid input (should return HTTP 400 and a clear error message)

To make your tests reliable, you can set the random seed or mock the random number generator so the results are predictable.

For example, in your test setup:

This way, your tests will always get the same dice rolls, making it easier to check the results.

Summary And Practice Preview

In this lesson, you explored how to enhance your Django API by supporting standard dice notation, ensuring robust input validation, and providing clear error messages for invalid requests. You also learned how to update your API endpoint to handle both dice notation and traditional parameters, and how to write tests to verify your parser and endpoint work correctly. With these skills, you are well-prepared to build more reliable and user-friendly Django applications. In the upcoming exercises, you’ll put these concepts into practice by parsing dice notation, validating input, and testing your API to reinforce what you’ve learned.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal