Handles non-existing objects in _copy_saved_objects API call (#158036)

Closes #156791

## Summary

This PR implements catching the error thrown by the
saved_objects_exporter when an object is not found, and responding with
a detailed 404 ("Not Found") rather than a generic 500 ("Internal Server
Error") response message.

### Example Response:
```
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Saved objects not found",
  "attributes": {
    "objects": [
      {
        "id": "7adfa750-4c81-11e8-b3d7-01146121b73d",
        "type": "dashboard"
      },
      {
        "id": "571aaf70-4c88-11e8-b3d7-01146121b73d",
        "type": "search"
      },
      {
        "id": "d3d7af60-4c81-11e8-b3d7-01146121b73d",
        "type": "index-pattern"
      }
    ]
  }
}
```

### Testing

1. Install sample flight data, find the id of the flights dashboard SO
2. Create an additional space 'b'
3. Issue a request to copy saved objects to space b
```
POST kbn:/api/spaces/_copy_saved_objects
{
  "spaces": [
    "b"
  ],
  "objects": [
    {
      "type": "dashboard",
      "id": "7adfa750-4c81-11e8-b3d7-01146121b73e"
    },
    {
      "type": "dashboard",
      "id": "7adfa750-4c81-11e8-b3d7-01146121b73f"
    },
    {
      "type": "dashboard",
      "id": "7adfa750-4c81-11e8-b3d7-01146121b73g"
    }
  ]
}
```
4. Verify response
```
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Saved objects not found",
  "attributes": {
    "objects": [
      {
        "type": "dashboard",
        "id": "7adfa750-4c81-11e8-b3d7-01146121b73e"
      },
      {
        "type": "dashboard",
        "id": "7adfa750-4c81-11e8-b3d7-01146121b73f"
      },
      {
        "type": "dashboard",
        "id": "7adfa750-4c81-11e8-b3d7-01146121b73g"
      }
    ]
  }
}
```
5. Issue a request to copy the flights dashboard SO
6. Verify the usual response (200, missing references)
7. Issue a malformed request to copy an SO
8. Verify status 400 response with details
This commit is contained in:
Jeramy Soucy 2023-05-24 12:20:46 -04:00 committed by GitHub
parent 668968b758
commit 1589547b6f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 13 deletions

View file

@ -36,6 +36,15 @@ Updates one or more saved objects to add and/or remove them from specified space
`spacesToRemove`::
(Required, string array) The IDs of the spaces the specified objects should be removed from.
[[spaces-api-update-objects-spaces-response-codes]]
==== Response codes
`200`::
Indicates a successful call.
`404`::
Indicates that the request failed because one or more of the objects specified could not be found. A list of the unresolved objects are included in the 404 response attributes.
[role="child_attributes"]
[[spaces-api-update-objects-spaces-response-body]]
==== {api-response-body-title}

View file

@ -105,19 +105,35 @@ export function initCopyToSpacesApi(deps: ExternalRouteDeps) {
})
);
const copySavedObjectsToSpaces = copySavedObjectsToSpacesFactory(
startServices.savedObjects,
request
);
const sourceSpaceId = getSpacesService().getSpaceId(request);
const copyResponse = await copySavedObjectsToSpaces(sourceSpaceId, destinationSpaceIds, {
objects,
includeReferences,
overwrite,
createNewCopies,
compatibilityMode,
});
return response.ok({ body: copyResponse });
try {
const copySavedObjectsToSpaces = copySavedObjectsToSpacesFactory(
startServices.savedObjects,
request
);
const sourceSpaceId = getSpacesService().getSpaceId(request);
const copyResponse = await copySavedObjectsToSpaces(sourceSpaceId, destinationSpaceIds, {
objects,
includeReferences,
overwrite,
createNewCopies,
compatibilityMode,
});
return response.ok({ body: copyResponse });
} catch (e) {
if (e.type === 'object-fetch-error' && e.attributes?.objects) {
return response.notFound({
body: {
message: 'Saved objects not found',
attributes: {
objects: e.attributes?.objects.map((obj: SavedObjectIdentifier) => ({
id: obj.id,
type: obj.type,
})),
},
},
});
} else throw e;
}
})
);