django-ninja: ValidationError includes other keys apart from the actual key

Hey @vitalik ,

Something that I noticed with the ValidationError being thrown is that there are additional fields present as opposed to the fields that are expected if the same ValidationError gets thrown from pydantic. The major problem with this is that when the client has to map this data to display the error to the user, it has to deliberately strip away a few fields all the time which doesn’t make sense.

For eg: The ValidationError that django-ninja gives for an invalid input:

{

    "detail": [
      {
        "loc": [
          "body", <---- whats this ? 
          "org", <------ and this  (the input param name I believe)?
          "name"
        ],
        "msg": "none is not an allowed value",
        "type": "type_error.none.not_allowed"
      },
      {
        "loc": [
          "body",
          "org",
          "address"
        ],
        "msg": "str type expected",
        "type": "type_error.str"
      },
      {
        "loc": [
          "body",
          "org",
          "org_type"
        ],
        "msg": "str type expected",
        "type": "type_error.str"
      }
   ]
}

The ValidationError that Pydantic gives for invalid input:

{
    "detail": [
      {
        "loc": [
          "name"
        ],
        "msg": "none is not an allowed value",
        "type": "type_error.none.not_allowed"
      },
      {
        "loc": [
          "address"
        ],
        "msg": "str type expected",
        "type": "type_error.str"
      },
      {
        "loc": [
          "org_type"
        ],
        "msg": "str type expected",
        "type": "type_error.str"
      }
   ]
 }

The latter is the one I expect django-ninja to return as well. I’d like to know your thoughts on this.

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Comments: 15 (6 by maintainers)

Most upvoted comments

Totally agree @blazing-gig that loc wrongly contains field names that’s not part of the schema, i.e. can’t be sent or known from a client’s perspective.

The second item, org in your example, is the one that shouldn’t be exposed in loc by ninja, since that is only a container for the posted body, and not a name/field that the client has sent or is visible in the OpenAPI schema.

Though, if a view have two body arguments, like the following example, then they should be part of loc IMO …

@api_router.post('/')
def foobar(request, a: SchemaA, b: SchemaB):
    ...

… since in this case the client would actually post data on fields a and b, and should therefor be part of loc.

About the first item in loc, body, I don’t agree. This is correct and should be present in both cases since the error is for a body param, i.e. the error’s location should tell the about its source; path, query or body.

FastAPI have had the same issue, but it was solved in this PR, omitting names that isn’t part of the client’s seen schema.

To solve this here, I think this might be the place to craft loc … we have full context, e.g. errors, view, request etc.

Thoughts or better placed fix @vitalik ?

Hey @vitalik ,

Here’s the api def

@org_api_router.post('/')
def org_create_view(request, org: OrgSchemaIn):
    created_org = Org.objects.create(**org.dict())
    return CustomResponseObj(
        status=StatusConstants.SUCCESS,
        data=OrgSchemaOut.from_orm(created_org)
    ).dict()