Admin API is not functioning as expected

I made the following test program with the function of app service.
“createUser”, “listUsers”, “getUser”, and “deleteUser” are tested.

const PROJECT_ID = '631b5cdefb...'
const APP_ID = '6331c3e8a3...'
const PUBLIC_API_KEY = 'dtn...'
const PRIVATE_API_KEY = '80792fcd-81e2...'

const API_BASE_URL = 'https://realm.mongodb.com/api/admin/v3.0'
const API_APP_BASE_URL = `${API_BASE_URL}/groups/${PROJECT_ID}/apps/${APP_ID}`

async function authenticate() {
  const result = await context.http.post({
    url: `${API_BASE_URL}/auth/providers/mongodb-cloud/login`,
    headers: {
      'Content-Type': ['application/json'],
      Accept: ['application/json']
    },
    body: {
      username: PUBLIC_API_KEY,
      apiKey: PRIVATE_API_KEY
    },
    encodeBodyAsJSON: true
  })
  return EJSON.parse(result.body.text())
}

async function listUsers(token) {
  const url = `${API_APP_BASE_URL}/users`
  console.log('log', '### listUsers url =', url)
  const response = await context.http.get({
    url: url,
    headers: {
      'Content-Type': ['application/json'],
      Authorization: [`Bearer ${token}`]
    },
    encodeBodyAsJSON: true
  })
  return response
}

async function createUser(token, email, password) {
  const url = `${API_APP_BASE_URL}/users`
  const response = await context.http.post({
    url: url,
    headers: {
      'Content-Type': ['application/json'],
      Authorization: [`Bearer ${token}`]
    },
    body: {
      email: email,
      password: password
    },
    encodeBodyAsJSON: true
  })
  return response
}

async function getUser(token, userId) {
  const url = `${API_APP_BASE_URL}/users/${userId}`
  console.log('log', '### getUser url =', url)
  const response = await context.http.get({
    url: url,
    headers: {
      'Content-Type': ['application/json'],
      Authorization: [`Bearer ${token}`]
    },
    encodeBodyAsJSON: true
  })
  return response
}

async function deleteUser(token, _id) {
  const url = `${API_APP_BASE_URL}/users/${_id}`
  console.log('log', '### deleteUser url =', url)
  const response = await context.http.delete({
    url: url,
    headers: { Authorization: [`Bearer ${token}`] }
  })
  return response
}

exports = async function() {
  const { access_token } = await authenticate()
  console.log('log', '### access_token =', access_token)
  {
    const response = await createUser(access_token, 'abcde1234', 'passwd-abcde1234')
    console.log('log', '### createUser response =', JSON.stringify(response))
  }
  {
    const response = await listUsers(access_token)
    console.log('log', '### listUsers response =', JSON.stringify(response))
  }
  {
    const response = await getUser(access_token, '63efc81da62aa1ff9ed9433b')
    console.log('log', '### getUser response =', JSON.stringify(response))
  }
  {
    const response = await deleteUser(access_token, '63efc81da62aa1ff9ed9433b')
    console.log('log', '### deleteUser response =', JSON.stringify(response))
  }
}

The results of the execute are as follows

log ### access_token = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
log ### createUser response = {"status":"201 Created","statusCode":201,"contentLength":-1,"headers":{"X-Envoy-Upstream-Service-Time":["4929"],"Date":["Sat, 18 Feb 2023 06:35:30 GMT"],"Content-Type":["application/json"],"Strict-Transport-Security":["max-age=31536000; includeSubdomains;"],"Vary":["Origin"],"X-Appservices-Request-Id":["63f071ad2640e1dc03da614d"],"X-Frame-Options":["DENY"],"Server":["mdbws"]},"body":{}}
log ### listUsers url = https://realm.mongodb.com/api/admin/v3.0/groups/631b5cdefb.../apps/6331c3e8a3.../users
log ### listUsers response = {"status":"200 OK","statusCode":200,"contentLength":-1,"headers":{"Vary":["Origin"],"Date":["Sat, 18 Feb 2023 06:35:34 GMT"],"X-Frame-Options":["DENY"],"X-Envoy-Upstream-Service-Time":["4034"],"Server":["mdbws"],"Cache-Control":["no-cache, no-store, must-revalidate"],"Content-Type":["application/json"],"Strict-Transport-Security":["max-age=31536000; includeSubdomains;"],"X-Appservices-Request-Id":["63f071b288d4013bd709a327"]},"body":{}}
log ### getUser url = https://realm.mongodb.com/api/admin/v3.0/groups/631b5cdefb.../apps/6331c3e8a3.../users/63efc81da62aa1ff9ed9433b
log ### getUser response = {"status":"200 OK","statusCode":200,"contentLength":-1,"headers":{"Cache-Control":["no-cache, no-store, must-revalidate"],"Strict-Transport-Security":["max-age=31536000; includeSubdomains;"],"Content-Type":["application/json"],"Vary":["Origin"],"X-Appservices-Request-Id":["63f071b62640e1dc03da62e3"],"X-Frame-Options":["DENY"],"Date":["Sat, 18 Feb 2023 06:35:38 GMT"],"X-Envoy-Upstream-Service-Time":["4035"],"Server":["mdbws"]},"body":{}}
log ### deleteUser url = https://realm.mongodb.com/api/admin/v3.0/groups/631b5cdefb.../apps/6331c3e8a3.../users/63efc81da62aa1ff9ed9433b
log ### deleteUser response = {"status":"204 No Content","statusCode":204,"contentLength":0,"headers":{"Date":["Sat, 18 Feb 2023 06:35:45 GMT"],"X-Appservices-Request-Id":["63f071ba88d4013bd709a481"],"X-Frame-Options":["DENY"],"Vary":["Origin"],"X-Envoy-Upstream-Service-Time":["6942"],"Server":["mdbws"],"Content-Encoding":["gzip"],"Strict-Transport-Security":["max-age=31536000; includeSubdomains;"]}}

When I checked the log, the status of “createUser” was 201 and the body was empty, but when I checked the UI, the user was created correctly.

The status of “listUsers” is 200, but the body is empty, and you can see more than a dozen accounts in the UI.

The status of “getUser” is also 200, but the body is empty, but the specified user ID is an ID created in advance by “createUser”, so it cannot be empty.

The status of “deleteUser” is 204, and the user with the specified ID has not been deleted when checked on the UI.

I am having trouble getting the expected results.
In particular, it is very difficult to implement because the user list cannot be obtained with “listUsers” and the target user cannot be deleted with “deleteUser”.
Could you let me know if you have any advice?
Thank you very much.

Hi @KENICHI_SHIMIZU,

Thanks for providing the code snippets and also redacting the sensitive info :slight_smile:

Just to clarify, would you be able to provide the following information / answers:

  • Use case details for the “test program” listed above?
  • Did you create and run the script in Atlas App Services Function Editor or from your local machine

I’m curious to understand if you plan on associating this function with a scheduled trigger or similar. In saying so, I look forward to hearing from you regarding the use case details.

Regards,
Jason

Thank you for your reply!

About the operation confirmation method,
All operations were performed on the WEB UI as shown in the attached screen.
I ran it with the RUN button circled in red.
If it goes well, I’d like to use it in data APIs, triggers, etc.
thank you.

Thanks for confirming @KENICHI_SHIMIZU,

I managed to replicate the same response you were encountering. For simplicity, i’ll be referencing the listUsers response in my test environment after making some slight changes:

log ### listUsers url = https://realm.mongodb.com/api/admin/v3.0/groups/<REDACTED/apps/<REDACTED>/users
log ### listUsers response = [{"_id":"63fc16a0a297115076e8dbdd","identities":[{"id":"63fc16a0a297115076e8dbd9","provider_type":"local-userpass","provider_id":"63fc16774a8677cf046792a5"}],"type":"normal","creation_date":1677465248,"last_authentication_date":0,"disabled":false,"data":{"email":"firstName.lastName@testemail.com"}},{"_id":"63fec06dbbc0299919efdb72","identities":[{"id":"63fec06dbbc0299919efdb68","provider_type":"local-userpass","provider_id":"63fc16774a8677cf046792a5"}],"type":"normal","creation_date":1677639789,"last_authentication_date":0,"disabled":false,"data":{"email":"abcde1234"}}]

I hope the above response is similar to what you are after. To achieve this, I had made the following changes to the code you had provided:

async function listUsers(token) {
  const url = `${API_APP_BASE_URL}/users`
  console.log('log', '### listUsers url =', url)
  const response = await context.http.get({
    url: url,
    headers: {
      'Content-Type': ['application/json'],
      Authorization: [`Bearer ${token}`]
    },
    encodeBodyAsJSON: true
  }).then(response => {
      const ejson_body = EJSON.parse(response.body.text());
      return ejson_body;
  })
  return response
}

The addition of .then() (and it’s contents) may help explain the difference in responses. The following Send an HTTP Request documentation may be of use.

Hope this helps.

If not, please advise what the response you are expecting is.

Regards,
Jason

2 Likes

Thanks @Jason_Tran
I was able to achieve my goal with the code you suggested.
I can only thank you.
:bowing_man: :bowing_man: :bowing_man: :bowing_man:

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.