Skip to content

REST API create empty content when "Content-Type" header is not defined #326

Open
@pomeh

Description

@pomeh

Describe the Bug

Creating a user via curl and REST API with a few fields defined creates an empty user.

To Reproduce

Create the user via curl:

$ curl -X POST -H 'Authorization: Bearer admin-token' "http://127.0.0.1:8055/users" -d '{ "email": "another@example.com", "first_name":"hello" }'
{"data":{"id":"3c8d7d56-ba17-49cb-a09e-2adf64c42587","first_name":null,"last_name":null,"email":null,"password":null,"location":null,"title":null,"description":null,"tags":null,"avatar":null,"language":null,"tfa_secret":null,"status":"active","role":null,"token":null,"last_access":null,"last_page":null,"provider":"default","external_identifier":null,"auth_data":null,"email_notifications":true,"appearance":null,"theme_dark":null,"theme_light":null,"theme_light_overrides":null,"theme_dark_overrides":null,"policies":[]}}

The token used belongs to an Admin user

-> the user is created, but both email and first_name fields are ignored during creation (the response includes "first_name":null,"email":null,, which is incorrect.)
-> using Directus app/admin access, we can see the user has been created, but all fields are empty too (this is coherent with the POST JSON response)

Note: I'm running a docker image derived from Directus v11.0.2, containing curl binary. All curl calls are done from inside this custom docker container (no nginx or other RP in between).

If I perform the same curl call again, I have exactly the same behavior, and another empty user is created.

Same behavior again with an "empty json body": curl -X POST -H 'Authorization: Bearer admin-token' "http://127.0.0.1:8055/users" -d '{}'.

After further investigations, I found the cause: my curl cause does not have Content-Type: application/json defined. Using curl -v, I can see curl defaults to Content-Type: application/x-www-form-urlencoded, which I guess Directus does not understand, then it reads the request body as "empty string" no matter what I send.

As soon as I add -H 'Content-Type: application/json' curl's option, the user is created with the given fields correctly set:

$ curl -H 'Content-Type: application/json' -X POST -H 'Authorization: Bearer admin-token' "http://127.0.0.1:8055/users" -d '{ "email": "hello@example.com", "first_name":"hello" }'
{"data":{"id":"e0bf25b6-f6b9-4619-a4eb-4ecf8592f993","first_name":"hello","last_name":null,"email":"hello@example.com","password":null,"location":null,"title":null,"description":null,"tags":null,"avatar":null,"language":null,"tfa_secret":null,"status":"active","role":null,"token":null,"last_access":null,"last_page":null,"provider":"default","external_identifier":null,"auth_data":null,"email_notifications":true,"appearance":null,"theme_dark":null,"theme_light":null,"theme_light_overrides":null,"theme_dark_overrides":null,"policies":[]}}

If I retry, I now get an expected error:

$ curl -H 'Content-Type: application/json' -X POST -H 'Authorization: Bearer admin-token' "http://127.0.0.1:8055/users" -d '{ "email": "hello@example.com", "first_name":"hello" }'
{"errors":[{"message":"Value for field \"email\" in collection \"directus_users\" has to be unique.","extensions":{"collection":"directus_users","field":"email","code":"RECORD_NOT_UNIQUE"}}]}

Still, I can call multiple times with empty JSON body:

$ curl -H 'Content-Type: application/json' -X POST -H 'Authorization: Bearer admin-token' "http://127.0.0.1:8055/users" -d '{}'
{"data":{"id":"4a190eca-aab5-4581-989e-43cd8b971ef5","first_name":null,"last_name":null,"email":null,"password":null,"location":null,"title":null,"description":null,"tags":null,"avatar":null,"language":null,"tfa_secret":null,"status":"active","role":null,"token":null,"last_access":null,"last_page":null,"provider":"default","external_identifier":null,"auth_data":null,"email_notifications":true,"appearance":null,"theme_dark":null,"theme_light":null,"theme_light_overrides":null,"theme_dark_overrides":null,"policies":[]}}

$ curl -H 'Content-Type: application/json' -X POST -H 'Authorization: Bearer admin-token' "http://127.0.0.1:8055/users" -d '{}'
{"data":{"id":"5637b9a7-9a55-4a6e-af7d-964122788e82","first_name":null,"last_name":null,"email":null,"password":null,"location":null,"title":null,"description":null,"tags":null,"avatar":null,"language":null,"tfa_secret":null,"status":"active","role":null,"token":null,"last_access":null,"last_page":null,"provider":"default","external_identifier":null,"auth_data":null,"email_notifications":true,"appearance":null,"theme_dark":null,"theme_light":null,"theme_light_overrides":null,"theme_dark_overrides":null,"policies":[]}}/

To recap, in my comprehension, there are 2 issues:

  1. Directus REST API should reject requests that does not have a valid Content-Type header (valid = a value Directus can handle correctly). Because according to the docs, The API uses JSON for input and output, and application/x-www-form-urlencoded is not JSON.

I also tried with 'Content-Type: application/whatever' and with no Content-Type header at all, in both case an empty user is created

  1. empty body should not be allowed in the POST payload. Even if all users fields are optionnals, it should detect empty payload and rejects with an error like "no payload found".

I didn't test other REST API endpoints, but my guess is the behavior would be the same for endpoints where all fields are optionals (some POST, probably all PATCH). This may be highly mistaken because:

  • you can create empty items in some collections
  • you may receive a 200 OK after a PATCH, you think the update has been done, but no update has been performed. So one would have to check the HTTP Code 200 + the JSON response to ensure all required update has been done

Last but not least: This also may explain the behavior reported in issue directus/directus#22826

Directus Version

v11.0.2

Hosting Strategy

Self-Hosted (Docker Image)

Database

sqlite

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions