Using Pydantic to validate inputs
Tags: python
Published: 2021-11-20 04:24:17

I continued to contribute to [partner-finder](https://github.com/codefordenver/partner-finder) which is one of Hacktoberfest the repo. 

## The issue: 
The repo owner posted a [issue](https://github.com/codefordenver/partner-finder/issues/144) on validating phone number, email address, social links and official user fields in the api of the project whenever there is a POST request to the server. 

## Solving: 
The repo owner suggested using [pydantic](https://pydantic-docs.helpmanual.io/) or [marshmallow](https://marshmallow.readthedocs.io/en/stable/) to make validating those fields easier. I decided to installed `pydantic` as it has better documents and I felt just right using it. 

### Validating phone number: 
I created a class `FieldTestModel` inheriting `BaseModel` with fields that needed validating. I then added a validator decorator to be parsed and validated in which I used regular expression to check the phone number.
```python 
class FieldTestModel(BaseModel):
        phoneNum: str
        assigned: str
        email: EmailStr
        socialLink: HttpUrl

        @validator("phoneNum")
        def check_phoneNumber_format(cls, v):
            regExs = (r"\(\w{3}\) \w{3}\-\w{4}", r"^\w{3}\-\w{4}$")
            if not re.search(regExs[0], v):
                return ValueError("not match")
            return v
```

### Validating email address, social links: 
Luckily, `pydantic` has its own field types that self-validate so I used `EmailStr` and `HttpUrl`, if there was any error, it would throw. 

### Validating assigned (official user): 
The data of `assigned` is an `username`, I needed to check if the `username` matches with one in the database. Firstly, I exported `getl_all_users` from a different module `users.py` to `leads.py` to use it. I simply checked if `assigned` presented in the array of users 
```python 
        @validator("assigned")
        def check_assigned(cls, v):
            users_response = get_all_users()
            if not users_response:
                raise ValueError("get_all_users() doesnt work")
            if v not in users_response["users"]:
                raise ValueError(f"{v!r} is not a registered user")
            return v
```
And the rest of the code 
```python 
    try:
        phoneNum = str(body.get("phone")).strip()
        assigned = body.get("assigned")
        email = EmailStr(body.get("email"))
        link = body.get("twitter")

        testInstance = FieldTestModel(phoneNum=phoneNum, assigned=assigned, email=email, socialLink=link)

        testInstance.socialLink = link
        link = body.get("facebook")
        testInstance.socialLink = link
        link = body.get("instagram")
        testInstance.socialLink = link
    except ValidationError as err:
        return {"message": "{error}".format(error=err.errors()[0])}
```

### Testing
I could test using `Postman` but instead I used the project's own api doc which includes a testing tool. Very cool! 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r1f8b5yk6qea9bnegc5s.png)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e36a8r3jq621nm44xptj.png)
You can check out my [PR](https://github.com/codefordenver/partner-finder/pull/227)