Changes to /admin/users/list/all.json API response structure?

Currently running Discourse 3.5.0.beta5-dev (eff31e0d42).

Would anyone know if the API response from the /admin/users/list/all.json endpoint has changed in the last week or so? :thinking:

Specifically:

GET /admin/users/list/all.json?email=email@example.com

:thinking:

I think this endpoint used to return a flat JSON object directly representing a single user when queried with an exact email address.

However, the current response structure now appears to wrap the user object inside a new users array, which has broken a few existing SSO integrations at our end.

Here is an anonymised pseudo example of the response of what I think has changed “before” and “after” for reference.

Old:

{
  "id": 1,
  "username": "sampleuser",
  "name": "",
  "avatar_template": "/user_avatar/example.com/sampleuser/{size}/avatar.png",
  "active": true,
  "admin": false,
  "moderator": false,
  "last_seen_at": "2025-05-11T08:27:28.578Z",
  "created_at": "2020-01-01T12:00:00.000Z",
  "suspended": false,
  "trust_level": 1
}

New:

{
  "users": [
    {
      "id": 1,
      "username": "sampleuser",
      "name": "",
      "avatar_template": "/user_avatar/example.com/sampleuser/{size}/avatar.png",
      "email": "someone@example.com",
      "active": true,
      "admin": false,
      "moderator": false,
      "last_seen_at": "2025-05-11T09:34:35.900Z",
      "created_at": "2020-01-01T12:00:00.000Z",
      "suspended": false,
      "trust_level": 1
    }
  ],
  "meta": {
    "message_bus_last_ids": {
      "bulk_delete": 0
    }
  }
}

Would anyone know of a recent commit that may have caused this change? :thinking:

It indeed changed and the commit is this

diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 92d906f161..70406efce5 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -32,7 +32,16 @@ class Admin::UsersController < Admin::StaffController
   def index
     users = ::AdminUserIndexQuery.new(params).find_users
 
-    opts = { include_can_be_deleted: true, include_silence_reason: true }
+    opts = {
+      include_can_be_deleted: true,
+      include_silence_reason: true,
+      root: :users,
+      meta: {
+        message_bus_last_ids: {
+          bulk_delete: MessageBus.last_id("/bulk-user-delete"),
+        },
+      },
+    }
     if params[:show_emails] == "true"
       StaffActionLogger.new(current_user).log_show_emails(users, context: request.path)
       opts[:emails_desired] = true

4 Likes

No amount of searching through the 73x commits I updated with yesterday found this DEV: replace selenium driver with playwright breaking change.

Thanks for the link @RGJ

1 Like

My approach:

  • load /admin/users/list/all.json?email=email@example.com
  • check the x-discourse-route header
  • look up the corresponding file (app/controllers/admin/users_controller.rb)
  • look up the corresponding method (index)
  • press “Blame”
  • spot the commit

5 Likes

Nooooo way… :scream:

Well, that’s what I learnt today!

Thanks @RGJ :clap:t2::star_struck:

2 Likes

I managed to find that commit somehow, but couldn’t (and still don’t) see where it changed the data structure (I was on my phone, making things a bit more difficult).

1 Like

I’m guessing this was the breaking change in the API response :confused:

In /app/assets/javascripts/admin/addon/controllers/admin-users-list-show.js

It’s the line root: :users that was added.

1 Like

We’ve now recovered from the impact of this change.

Perhaps going a bit off topic here but is there a way I can track these types of updates so I can notify myself when an API response changes from “X”, after being “Y” for so many years? :thinking:

Some kind of scripted local unit tests that I could run on a daily basis perhaps?

Although now I’ve said that out loud, that wouldn’t notify me until after I’d updated my Discourse and it had broken the integrations.

A staging environment I guess…

You could have a staging environment. You might also create a github action for your code that starts discourse and runs a test against the latest discourse each day.

2 Likes

Ah-ha! Perfect, that’d work, thanks :grin:

1 Like

I think a plugin that called the endpoint and rendered it could be an easy way to test. And then change the default github action to run daily instead of only on push.

1 Like

Seems the documentation needs an update as well https://docs.discourse.org/#tag/Admin/operation/adminListUsers

In an ideal world, the documentation would be auto generated from the source and we could just look at the commit history for the documentation, which would only contain the changes in the interface.

3 Likes

This is what caught me out too when trying to resolve the issues caused by this change :confused: