blob: ffc2ef25b45dfd99b6a4142e9db75fad26a3afd5 [file] [log] [blame] [view] [edit]
# 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.