Yes,
GET /api/companies/1/employees
would be the way to get the employees of a company.
What exactly your employee resource offers would depend on some details of your application. For example you could have logins for admins that are directly related to a specific company. It this case it would be a possible shortcut the employees resource and directly go to an employee or list of employees. But in normal cases /api/employees would only work in combination with companies.
Very interesting question would be the nesting levels. This is one of the questions some people can discuss for hours. Ruby on Rails for example has now an option for "shallow" routes.
While there is no hard technical limit to the number of levels (max length of an URL maybe) I think two levels should be enough for most cases and deeper nesting should be avoided if possible since doing so will make your code better structured and maintainable.
Your example is quite typical and it is easy to show why you would not really need a third level for the tasks in most scenarios. Your tasks are directly related to an employee. So the entity resource somehow already carries the information about the company. (Selecting an employee automatically selects the company). So providing the company in the URL again somehow repeats information.
GET /api/employees/123/tasks
has all the information necessary to get to your data. So why make it more complex?
I'm not sure if I fully understand your last question.
Restricting access in this context is rather easy. Say you have a client who has only access to resources of the company with id 123. Then all you have to do is to start your controller code by assigning some "hard limits". If the logged in user is not allowed to access anything but one company, then create an obkect for that company and from there on use only this object for any firther access.
Assume we have a Rails projects. For this we have a model for each resource you mention. In addition we have an authentication system in place that gives us the currently logged in user. In this case it would be as easy as this to return something like the list of employees:
current_user.company.employees
Notice that it does not even try to use any company id used in the URL (which in case of Rails would be stored in params[:company_id]).
Try to get the tasks of a specific employee with
GET /api/companies/123/employees/456/tasks
current_user.company.employees.find(params[employee_id]).tasks
Notice again that this is going the "full path" instead of simply using
Employee.find(params[employee_id]).tasks
The first form will create a SQL query with a lot of LEFT JOINS that starts from user, goes through company, employees and tasks. And important in this case: It will fail if a single relation is missing.
Even if not in context of a login and permissions you can still use this to enforce that the user has a certain knowledge about the data. Though in this case you would maybe have to use deeper nested routes. Same example without login but the user making the request must know the correct company id. In this case:
GET /api/companies/123/employees/456/tasks
Company.find(params[:company_id]).employees.find(params[employee_id]).tasks
Again go the full way. If your framework does not have this kind of object relations simply nake sure that your SQL requests use JOINS in a similar fashion.
The first question you need to answer is whether you intend to create a truly generic data access framework, or if you want it tailored to the particular project you're working on.
A generic framework has the benefit of being portable and fairly loosely coupled to the underlying DB + schema, but at the cost of pushing schema level information further up in the framework. The more generic you make the framework, the more of this knowledge you push up.
A tailored framework alleviates the higher levels of the application from worrying about the schema or DB details, but at the cost of cost of being less re-usable in other environments. As a corollary, the more specific you make the framework, the less easy it is to extend elsewhere.
If you're not sure on which of those to pick, the generic framework makes sense if you suspect there will be changes at the DB layer or the schema. Likewise, if those are pretty well locked down then the tailored framework is the better approach. Ultimately, you're optimizing the system to more easily handle where you think the change will occur.
As to whether or not you should refactor - the answer is No unless you're encountering a specific problem.
Worrying about the degree of coupling is nice, I suppose, but doesn't necessarily address a specific problem that you may be seeing. Refactoring based upon presumed issues within coupling is actually more likely to create a problem for you than just leaving it alone.
Likewise with expressing the state. If the current mechanism of an enum
is sufficient and doesn't present an apparent problem then don't change what you've got.
Overall, it sounds like you've designed a reasonably robust data access method for the domain you're working worth. Your question doesn't list any specific issues that are holding back your development, so I'd call it good and move to the next stage of development.
Best Answer
Due to no link to StackOverflow has been shared, I just want to mention why is code smell.
In short:
it would introduce undesirable coupling. Potentially one of the DAOs would end up subordinated to the other.
It has all the recipes for a circular dependency. See also Circular references.
Regarding to the code (the exmaple of
DBService
)So far, the code is at the doors of the well known Repository pattern (despite the actual name) which is broadly adopted by the community. You will find many references to the pattern looking for DDD.
The Repository pattern introduced in Eric Evans' DDD, has nothing to do with the implementation details, so the implementation will vary according to the specific requirements and needs.
What doesn't vary is the concept. The purpose.
So, based only in the info you provide, I would say that you are doing fairly good.