Sync API: Asynchronous error handling

Context of this document: The Flip Sync API for users and channels

Please find the specifications for reading states and errors of asynchronous requests with the link below.

Flip API Documentation

 

Getting error messages

Asynchronous communication is used for activities that require more processing time, which makes it inappropriate to wait for the result actively. The communication then proceeds so that after establishing a connection with the server and sending the data, the server validates the request (with the caveat that here it may still synchronously respond with HTTP 400 Bad Request) and responds with HTTP 202 Accepted. At that point, the request was passed internally for further processing, and the current connection was terminated.

To track errors that happen asynchronously, API calls can be given or grouped by “names” or, as they are called in the JSON objects, request_context. This allows you to perform a single large task over multiple requests and still retrieve an aggregation of all status information and related errors. For example, a context could be "user_migration_3.8.2022". This feature is optional. If left unspecified, the request_context is set to a unique random value, which can be used to access that single request later.

Please note that if you assign the same request context to multiple requests to group them, you cannot access them individually again since all errors with that request context are shown.

After your request has been accepted successfully, you will likely want to track its processing status until completion. Our api/external/v1/requests/{request_context} endpoint provides the functionality. Replace request_context with the value you received in the request's response to the User- and Groups Sync-API. Its response contains the number of work items that have been processed already for your request and how many ended up causing errors. Refer to the API specification for more detailed information.

{
    batch_size: 100,
    batch_items_completed: 42,
    errors: 2
}

In case any errors occur during the processing of your request, we provide the api/external/v1/requests/{request_context}/error endpoint to access detailed information for all errors. Replace request_context with the value you received in the request's response to the User- and Groups Sync-API. This endpoint supports pagination of the error list, so your response will contain a (possible subset) list of all errors named errors and a cursor object to fetch the next page, if any, called next_cursor. Refer to the API specification for more detailed information.

{
    "errors": [
        {
            "error_cause": "External Id is blank",
            "error_name": "validation",
            "item": {
                "user_external_id": "7170346245"
            },
            "reported_at": "2022-07-18T08:05:48.975425Z"
        }
    ],
    "next_cursor": {
        "after": "rO0A.......NKUA==",
        "has_more": false
    }
}

 

Overview of possible errors

Errors that occur when creating, updating, or deleting groups and users are collected. Since these processes take some time and are handled asynchronously, they cannot be returned directly as HTTP Error Codes. This means an error happens after the original HTTP call is terminated.

The different errors that are possible in the JSON are:

Title errorName errorCause description
external id blank validation External Id is blank The external ID of the user is not provided but is required to update the user.
password history identitiy_provider Invalid password history: followed by a detailed message (e.g., must not be equal to any of the last 3 passwords) The password history tracks each user's passwords individually so that a user cannot reuse one of the last passwords. Info: The password history count (in our example, the last 3 passwords) is individual per customer.
password policy identity_provider Password policy not met: followed by a detailed message (e.g., Invalid password: minimum length 8 or Invalid password: must not be equal to the username) This covers the cases of passwords that are too long, passwords that are too short, special characters missing, etc. For details about your password rules, ask your Flip CS Contact person.
general error - user creation identity_provider User cannot be created: followed by a detailed message General error for all cases during the creation of a user.
general error - update identity_provider Required action cannot be set: followed by a detailed message General error that happens during an update action if Keycloak (our Identity and Access Management System) is unreachable for a short time.
group name exceeds limit validation Invalid length of group name: followed by a detailed message Group name exceeds the maximum allowed length (currently 120 characters).
group description exceeds limit validation Invalid length of group description: followed by a detailed message Group description exceeds the maximum allowed length (currently 200 characters).
group id does not exist not_found No group with group ID = '{group_id}' exists. containing the group_id A Group ID is provided when a Group is created or updated, but no Group with the given ID exists.
last_modified in the future validation last_modified_at must not be too far in the future. followed by a detailed message Last Modified of a User or Group is set to more than 1 year in the future.
username contains whitespace validation Username must not contain any whitespaces. followed by a detailed message Username contains whitespace chars (or tab, newline,…)
External Group ID blank validation External Group Id is blank. No External Group ID is provided, but a group_memberships field is present in a create or update User request.
Duplicate Username validation There is already a user with the username = '{username}'. containing the given username Duplicate assignment of identical username.
Group name blank validation Group name is blank. Group name is empty or not provided.
External User ID does not exist not_found No User with given external ID exists. The External User ID specified when deleting a user does not exist.
length limit exceeded validation Invalid length of {propertyName}. followed by a detailed message Properties of User or User Profile exceed the maximum length.
External Group Id doesn’t exist not_found
No group with external ID = '{external_Id}' exists., containing the external_id No group with the specified external ID exists.


Example: external id blank

{
  "request_context": "my-context",
  "users": [
    {
      "system_role": "USER",
      "external_id": "my-external-id",
      "username": "username",
      "first_name": "firstname",
      "last_name": "lastname",
      "tags": [
        {
          "key": "memberOf",
          "value": ""
        }
      ]
    }
  ]
}


Example: password policy

{
  "request_context": "my-context",
  "users": [
    {
      "system_role": "USER",
      "external_id": "my-external-id",
      "username": "username",
      "first_name": "firstname",
      "last_name": "lastname",
      "login": {
        "password": {
          "password": "tooshort",
          "temporary": true
        }
      }
    }
  ]
}


Example: password history

{
  "request_context": "my-context",
  "users": [
    {
      "system_role": "USER",
      "external_id": "my-external-id",
      "username": "username",
      "first_name": "firstname",
      "last_name": "lastname",
      "login": {
        "password": {
          "password": "VerY-GoOd-PassW%rd!",
          "temporary": true
        }
      }
    }
  ]
}

 

Complete example of a successful and failed case of a request for user creation

The example shows the entire creation of a user, but the steps are the same for all asynchronous operations.

Requesting the creation of a user (successful case)

POST /api/external/v2/sync/users HTTP/1.1
Accept: application/json
Authorization: Bearer eyJh...
Content-Type: application/json
Host: flipapp.de

{
    "request_context": "my-context",
    "users": [
        {
            "confirm_terms_and_conditions": "ASK_ON_NEXT_LOGIN",
            "external_id": "6fe424c308",
            "first_name": "40d5fb76",
            "last_name": "40d5fb76",
            "login": {
                "password": {
                    "password": "Password",
                    "temporary": true
                }
            },
            "system_role": "USER",
            "username": "40d5fb76"
        }
    ]
}

Response:

HTTP/1.1 202 Accepted
Content-Type: application/json

{
    "request_context": "my-context"
}

 

Checking possible errors (successful case)

GET /api/external/v1/requests/my-context/errors HTTP/1.1
Accept: application/json
Authorization: Bearer eyJh...
Connection: keep-alive
Host: flipapp.de

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "errors": [],
    "next_cursor": {
        "has_more": false
    }
}

There were no errors in this case, so the list is empty.


Requesting the creation of a user (failed case)

POST /api/external/v2/sync/users HTTP/1.1
Accept: application/json
Authorization: Bearer eyJh...
Content-Type: application/json
Host: flipapp.de

{
    "request_context": "my-context",
    "users": [
        {
            "external_id": "a3ef74bdde",
            "first_name": "firstname",
            "last_name": "lastname",
            "system_role": "USER",
            "tags": [
                {
                    "key": "memberOf",
                    "value": ""
                }
            ],
            "username": "ea0298c5"
        }
    ]
}

Response:

HTTP/1.1 202 Accepted
Content-Type: application/json

{
    "request_context": "my-context"
}

 

Checking possible errors (failed case)

GET /api/external/v1/requests/my-context/errors HTTP/1.1
Accept: application/json
Authorization: Bearer eyJh...
Host: flipapp.de

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "errors": [
        {
            "error_cause": "External Id is blank",
            "error_name": "validation",
            "item": {
                "user_external_id": "a3ef74bdde"
            },
            "reported_at": "2022-08-08T13:40:19.218601Z"
        }
    ],
    "next_cursor": {
        "after": "rO0...",
        "has_more": false
    }
}

There is one error in the error list.

Was this article helpful?

0 out of 0 found this helpful

Have more questions? Submit a request

Comments

0 comments

Please sign in to leave a comment.