| # Build API Endpoint Tutorial Part 3 |
| |
| This README is a continuation of |
| [Hello World Tutorial Part 2](2_hello_target.md), |
| creating a "Hello world!" endpoint from scratch. |
| This tutorial assumes you have already executed all the steps in Part 1 and 2, |
| and have all the code in place. |
| |
| ## Hello World Part 3: Validation |
| |
| In this tutorial, we'll be looking at argument validation in Build API |
| endpoints. |
| This provides a hands-on walkthrough of how to use the validation functionality |
| in the Build API. |
| For a full listing of all the validators, and more details about their |
| functionality see the [validation reference](../references/validation.md). |
| |
| ### "Hello, !"?!? |
| |
| What happens when you don't pass a value for `target`? |
| In Part 2, if you tried running `./hello__hello` before updating |
| `hello__hello_input.json`, you may have already seen this output. |
| Let's look at it now. |
| |
| ```shell script |
| $> cd ~/chromiumos/chromite/api/contrib/call_scripts/ |
| $> mv hello__hello_input.json hello__hello_input.json.bak |
| $> echo "{}" > hello__hello_input.json |
| $> ./hello__hello |
| Running chromite.api.HelloService/Hello |
| 15:18:22: DEBUG: Services registered successfully. |
| Hello, ! |
| Completed chromite.api.HelloService/Hello |
| Success! |
| Return Code: 0 |
| Result: |
| {} |
| ``` |
| |
| Most importantly: |
| |
| ```text |
| Hello, ! |
| ``` |
| |
| #### So what happened? |
| |
| Since we didn't specify `target`, proto used the default value for the field. |
| The default value of every field in proto3 is the False-y/empty/0 value for the |
| type. |
| Since `target` is a `string`, the default value is an empty string, while the |
| numeric types and enums default to 0, and bools default to False. |
| |
| #### How do we fix it? |
| |
| Validation! |
| Saying hello to nothing doesn't seem very useful, so we should check in the |
| endpoint that we do always have a target. |
| The Build API has a series of validation decorators for checking the contents |
| of the input proto. |
| For now, we'll just look at the validation for our new endpoint. |
| |
| What we want is for `target` to always have a value. |
| For that, we use the `@validate.require` decorator. |
| As the name suggests, the require validator requires that the field has a value. |
| In practice, this means that the field must have a *non-Falsey* value! |
| |
| **Important:** Because protobuf's default values are the Falsey values, and so |
| consequently protobuf does not differentiate between passing a Falsey value and |
| not passing a value at all, neither can we! |
| |
| `chromite/api/controller/hello.py`: |
| ```python |
| from chromite.api import validate |
| from chromite.lib import hello_lib |
| |
| @validate.require('target') |
| @validate.validation_complete |
| def Hello(request, response, config): |
| hello_lib.hello(target=request.target) |
| ``` |
| |
| So, what do we have here? |
| |
| `@validate.require('target')`: |
| This line is our actual validation, requiring `request.target` to have a |
| value. |
| |
| `@validate.validation_complete`: |
| This line should be added on every function where all validation is completed |
| by the `@validate` decorators. |
| As a part of the Build API extended functionality, it allows validation-only |
| calls to endpoints. |
| These validation-only calls execute the input validation, and then exit. |
| The purpose is to allow validation of client implementation on old, branched |
| versions of the Build API. |
| |
| #### Validating validation |
| |
| Let's check that worked. |
| |
| ```shell script |
| $> cd ~/chromiumos/chromite/api/contrib/call_scripts/ |
| $> ./hello__hello |
| Running chromite.api.HelloService/Hello |
| 16:23:34: DEBUG: Services registered successfully. |
| 16:23:34: DEBUG: Validating target is set. |
| 16:23:34: ERROR: target is required. |
| Completed chromite.api.HelloService/Hello |
| Return Code: 1 |
| Result: |
| ``` |
| |
| Instead of "Hello, !", we got an error! |
| Now let's check our old "moon" target to make sure it still works. |
| |
| ```shell script |
| $> mv ./hello__hello_input.json.bak ./hello__hello_input.json |
| $> ./hello__hello |
| Running chromite.api.HelloService/Hello |
| 16:29:47: DEBUG: Services registered successfully. |
| 16:29:47: DEBUG: Validating target is set. |
| Hello, moon! |
| Completed chromite.api.HelloService/Hello |
| Success! |
| Return Code: 0 |
| Result: |
| {} |
| ``` |
| |
| Success! |
| |
| |
| ## Up Next |
| |
| Continue to [Part 4](4_hello_faux.md), where we'll look at mock calls and |
| the faux decorators. |