Description
Issue
I expected the SDK to throw errors when I retrieve an item by its ID. Instead, I received undefined
.
There are other methods from the SDK that throw actual errors when DB operation failed, and having one method that returns undefined
confuses me which doesn't help me with keeping a consistent approach for error-handling in my app.
Setup
- Package Name:
@azure/cosmos
- Package Version: 4.0.0
- Operating system: W11
- nodejs
- version: 18.18.0
- browser
- name/version:
- typescript
- version: 5.2.2
Describe the bug
When we retrieve item by IDs, we're expecting the SDK to throw an error when no item in the container has been found. Instead, we're receiving undefined
as we retrieve item using invalid IDs.
In the source code snippet, it seems that the desired behaviour is to throw errors when error.code !== StatusCodes.NotFound
, which means any other errors will be treated as a response to then be returned without throwing errors.
To Reproduce
Steps to reproduce the behavior:
// future-state-role.repository.ts
import { Inject, Service } from 'typedi';
import { ResultAsync, err, ok } from 'neverthrow';
@Service()
export class FutureStateRoleRepository {
protected className: TRepository = 'FutureStateRoleRepository';
constructor(
@Inject() private cosmosService: CosmosService,
) {}
protected get container() {
const url = env.COSMOS_DB_CONNECTION_STRING;
const database: Database = 'DatabaseName';
const container: Container = 'FutureStateRole';
const cosmosClient = this.cosmosService.createCosmosClient(url);
if (!cosmosClient) {
throw new Error('Failed to create CosmosClient!');
}
return cosmosClient.database(database).container(container);
}
public async findOne(
args: FutureStateRoleFindUniqueArgs,
): Promise<ResultAsync<FutureStateRole, CustomError>> {
// assume id is 'randomValue` -> which isn't an actual ID
const { id } = args.where;
const response = await this.container.item(id, id).read<FutureStateRole>(); // will return 'undefined'
// custom error-handling logic
if (response.resource === undefined) {
const errArgs: TCustomError = {
scope: this.className,
function: 'findOne',
message: 'Failed to find FutureStateRole, please provide a valid ID',
};
return err(new CustomError(errArgs));
}
const serialisedData =
this.crud.serialiseDateStringsToDateObject<FutureStateRole>(
response.resource,
);
return ok(serialisedData);
}
}
// cosmos.service.ts
import { Service } from 'typedi';
import { CosmosClient } from '@azure/cosmos';
@Service()
export class CosmosService {
private cosmosClients: { [connecion: string]: CosmosClient } = {};
public createCosmosClient(connectionString: string): CosmosClient {
if (!this.cosmosClients[connectionString]) {
this.cosmosClients[connectionString] = new CosmosClient(connectionString);
}
return this.cosmosClients[connectionString];
}
public getCosmosClient(connectionString: string): CosmosClient | undefined {
return this.cosmosClients[connectionString];
}
}
Expected behavior
I expected this.container.item(id, id).read()
to throw error if id
doesn't match any item in the container, instead of receiving undefined
Additional context
If there is a particular reason why returning undefined
makes more sense, please let me know.