When using UploadedFile in the PUT method of ninja Router? I get ["detail": \[{"loc": \["body", "profile_in"\], "msg": "field required"]

184 views Asked by At

I'm trying to add an UploadedFile parameter to the PUT method in my Ninja router. The same parameter works perfectly fine with the POST method, but when I try to use it with the PUT method, Ninja returns the error:

Code
422

Details Error: Unprocessable Entity

Response body

{
  "detail": [
    {
      "loc": [
        "body",
        "profile_in"
      ],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}

which doesn't make sense to me, because I'm passing all the required parameters in the profile_in. here's the curl command that the swagger is providing:

curl -X 'PUT' \
  'http://127.0.0.1:8000/api/profile/edit_profile' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <My Token>' \
  -H 'Content-Type: multipart/form-data' \
  -F 'img=@IMG_20220425_094322_906.JPG;type=image/jpeg' \
  -F 'profile_in={
  "name": "Hassan",
  "title": "Web",
  "bio": "string",
  "skills": [
    {
      "name": "Django"
    },
    {
      "name": "HTML/CSS"
    }
  ]
}'

here is my post method:

@profile_controller.post("create_profile",
                         response={200: ProfileSchemaOut, 
                                   404: MessageOut,
                                   400: MessageOut,
                                   },
                        auth=CustomAuth(),
                        )
def create_profile(request, profile_in:ProfileSchemaIn, img:UploadedFile=None):

and the put method:

@profile_controller.put("edit_profile",
                         response={200: ProfileSchemaOut, 
                                   404: MessageOut,
                                   400: MessageOut,
                                   },
                        auth=CustomAuth(),
                        )
def edit_profile(request, profile_in: ProfileSchemaIn, img:Optional[UploadedFile]=File(None)):

I don't know if this is relevant but this is my ProfileSchemaIn

class ProfileSchemaIn(ProfileSchema):
    name: str
    title: str
    bio: Optional[str] = None
    skills: Optional[List[SkillSchema]]

I know I can use bas64 for storing the img but I want to use the UploadedFile

1

There are 1 answers

1
GentlePandaTakedown On

Upon examining the provided curl command and your code, I noticed that the curl command is missing the 'img' parameter. Additionally, the 'profile_in' parameter should be passed as separate form fields instead of being embedded in a JSON string.

Here's an updated curl command that includes the 'img' parameter and passes the 'profile_in' parameters as separate form fields:

curl -X 'PUT' \
  'http://127.0.0.1:8000/api/profile/edit_profile' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <my token>' \
  -H 'Content-Type: multipart/form-data' \
  -F 'name=Hassan' \
  -F 'title=Web Developer' \
  -F 'bio=string' \
  -F 'skills=[{"name":"Django"}]' \
  -F 'img=@/path/to/your/image.jpg'

For your Ninja router methods, the input parameters should be defined as follows:

from pydantic import BaseModel
from typing import List

class ProfileInput(BaseModel):
    name: str
    title: str
    bio: Optional[str] = None
    skills: Optional[List[SkillSchema]]

@profile_controller.post("create_profile",
                         response={200: ProfileSchemaOut, 
                                   404: MessageOut,
                                   400: MessageOut,
                                   },
                        auth=CustomAuth(),
                        )
def create_profile(request, profile_in: ProfileInput = Body(...), img: UploadedFile = File(None)):

@profile_controller.put("edit_profile",
                         response={200: ProfileSchemaOut, 
                                   404: MessageOut,
                                   400: MessageOut,
                                   },
                        auth=CustomAuth(),
                        )
def edit_profile(request, profile_in: ProfileInput = Body(...), img: Optional[UploadedFile] = File(None)):