Answer the question
In order to leave comments, you need to log in
Should the same endpont in a RESTlike API be made available to both authorized and non-authorized users?
Hello.
Let's say I want to do a blog platform api. I provide consumers with the following endpoint:
/blogs?usrId={someValue}&filter[published]={someValue}
And now I have to consider several options in the code, namely:
Authorized or not authorized request = 2 options
uresId specified or not = 2 options Filter
values [published] : undefined, true, false = 3 options
In total, we need to consider 2 * 2 * 3 = 12 cases and issue either data or an authorization error.
It confuses me that it is necessary to check so many conditions, is this normal in one controller? Or is there some other way to organize such logic, let's say make two endpoints, but then how to call them?
Tell me your thoughts please?
UPD:
This is what I had to write:
const {
userId,
filter: { published },
} = params;
const qb = this.blogRepository
.createQueryBuilder()
.select(['id', 'title', '"createdAt"'])
.addSelect('SUBSTRING(body, 1, 300)', 'body');
if (currentUser) {
// request authorized
if (userId) {
qb.where('"userId" = :userId', { userId });
if (published === Published.unpub) {
if (currentUser.id === userId) {
qb.andWhere('published = :published', { published });
} else {
throw new UnauthorizedError();
}
} else if (published === undefined) {
if (currentUser.id !== userId) {
qb.andWhere('published = :published', {
published: Published.pub,
});
}
} else {
qb.andWhere('published = :published', {
published: Published.pub,
});
}
} else {
if (published === Published.unpub) {
qb.where('published = :published', { published }).andWhere(
'"userId" = :userId',
{ userId: currentUser.id }
);
} else if (published === undefined) {
qb.where('published = :published', {
published: Published.pub,
}).orWhere(
new Brackets((qb1) => {
qb1
.where('published = :published', { published: Published.unpub })
.andWhere('"userId" = :userId', { userId: currentUser.id });
})
);
} else {
qb.andWhere('published = :published', { published });
}
}
} else {
// request not authorized
if (userId) {
qb.where('"userId" = :userId', { userId });
if (published === Published.unpub) {
throw new UnauthorizedError();
} else {
qb.andWhere('published = :published', { published: Published.pub });
}
} else {
if (published === Published.unpub) {
throw new UnauthorizedError();
} else {
qb.andWhere('published = :published', { published: Published.pub });
}
}
}
Answer the question
In order to leave comments, you need to log in
if you need to implement 12 logical options, then you will have to implement them, it’s another matter that they use approaches that speed up their implementation:
usually the scheme is like this, you “inherit” your request from some object with already prepared GENERAL functionality for requests, for example, to check authorization and return the corresponding errors.
and you parse the request-specific parameters, and if they are absent, you replace them with the default parameters and work as you did, or you give some errors there
It is not worth doing different endpoints, it is better to do JWT authorization and then your checks will be reduced by 2 times.
You need to rethink your API. Both options so far seem wild. If you detail what your api is, what this particular method does, then you can help make a decision.
In general:
- select the entities of the system (Entities of Domain Model at least)
- make a list of roles and actions that they do (UseCase)
- this is where it starts to clear up
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question