Isn't resource-oriented really object-oriented? - rest

When you think about it, doesn't the REST paradigm of being resource-oriented boil down to being object-oriented (with constrained functionality, leveraging HTTP as much as possible)?
I'm not necessarily saying it's a bad thing, but rather that if they are essentially the same very similar then it becomes much easier to understand REST and the implications that such an architecture entails.
Update: Here are more specific details:
REST resources are equivalent to public classes. Private classes/resources are simply not exposed.
Resource state is equivalent to class public methods or fields. Private methods/fields/state is simply not exposed (this doesn't mean it's not there).
While it is certainly true that REST does not retain client-specific state across requests, it does retain resource state across all clients. Resources have state, the same way classes have state.
REST resources are are globally uniquely identified by a URI in the same way that server objects are globally uniquely identified by their database address, table name and primary key. Granted there isn't (yet) a URI to represent this, but you can easily construct one.

REST is similar to OO in that they both model the world as entities that accept messages (i.e., methods) but beyond that they're different.
Object orientation emphasizes encapsulation of state and opacity, using as many different methods necessary to operate on the state. REST is about transfer of (representation of) state and transparency. The number of methods used in REST is constrained and uniform across all resources. The closest to that in OOP is the ToString() method which is very roughly equivalent to an HTTP GET.
Object orientation is stateful--you refer to an object and can call methods on it while maintaining state within a session where the object is still in scope. REST is stateless--everything you want to do with a resource is specified in a single message and all you ever need to know regarding that message is sent back in a single response.
In object-orientation, there is no concept of universal object identity--objects either get identity from their memory address at any particular moment, a framework-specific UUID, or from a database key. In REST all resources are identified with a URI and don't need to be instantiated or disposed--they always exist in the cloud unless the server responds with a 404 Not Found or 410 Gone, in whch case you know there's no resource with that URI.
REST has guarantees of safety (e.g., a GET message won't change state) and idempotence (e.g., a PUT request sent multiple times has same effect as just one time). Although some guidelines for particular object-oriented technologies have something to say about how certain constructs affect state, there really isn't anything about object orientation that says anything about safety and idempotence.

I think there's a difference between saying a concept can be expressed in terms of objects and saying the concept is the same as object orientation.
OO offers a way to describe REST concepts. That doesn't mean REST itself implements OO.

You are right. Dan Connolly wrote an article about it in 1997. The Fielding thesis also talks about it.

Objects bundle state and function together. Resource-orientation is about explicitly modeling state(data), limiting function to predefined verbs with universal semantics (In the case of HTTP, GET/PUT/POST/DELETE), and leaving the rest of the processing to the client.
There is no equivalent for these concepts in the object-orientation world.

Only if your objects are DTOs (Data Transfer Objects) - since you can't really have behavior other than persistence.

Yes, your parallel to object-orientation is correct.
The thing is, most webservices (REST, RESTful, SOAP,..) can pass information in the form of objects, so that isn't what makes it different. SOAP tends to lead to fewer services with more methods. REST tends to lead to more services (1 per resource type) with a few calls each.

Yes, REST is about transfer of objects. But it isn't the whole object; just the object's current state. The implicit assumption is that the class definitions on both sides of the REST are potentially similar; otherwise the object state has been coerced into some new object.
REST only cares about 4 events in the life on an object, create (POST), retrieve (GET), update (PUT) and delete. They're significant events, but there's only these four.
An object can participate in lots of other events with lots of other objects. All the rest of this behavior is completely outside the REST approach.
There's a close relationship -- REST moves Objects -- but saying they're the same reduces your objects to passive collections of bits with no methods.

REST is not just about objects, its also about properties :: a post request to /users/john/phone_number with a new phone number is not adding a new object, its setting a property of the user object 'john'
This is not even the whole state of the object, but only a change to a small part of the state.
It's certainly not a 1:1 match.

Related

RPC vs restful endpoints

I've spent more time than I'd like to admit trying to understand the differences between RPC and restful endpoints. In fact, after going down this rabbit hole, I'm not even sure I fully understand what RPC is anymore. And I'm not alone. I see countless messages repeatedly asking for clarification.
Here's my understanding so far:
RPC and restful endpoints are largely conceptual in nature only. There are no standards.
Both are ways of invoking a function on a remote server.
In the case of restful endpoints, we map HTTP methods to CRUD operations on a resource.
In the case of RPC, we're concerned w/actions on an object.
However, in both cases, we're addressing remote method invocation.
I've read some folks say restful shouldn't be stateful and if it is, it's not restful. But aren't most restful endpoints using state via sessions? I mean, I'm not going to let just anyone delete data w/o being logged in.
And I've also read that functions like domain(.)com/login isn't restful b/c it's an action. This seems to make sense, but since I'm not writing my functions any differently on my server than I would a simple restful function, does it really matter what we call them -- restful vs. RPC.
I truly just don't understand what I'm missing and no posts thus far on StackOverflow appear to address this confusion.
Hoping someone can provide some insight using the above as a guide for understanding. Thanks in advance.
It's an amazing question. There is a huge difference between REST and RPC approaches, I'll try to explain it.
RPC just lets you call some remote computer to make some job. It can be any job, and it can have any inputs and outputs. When you design API, you just define how to name this job operation and which inputs and outputs it will have.
Step 1. Just RPC
For example, you could have operation foo with one input and two outputs like that (I will use JSight API notation because it supports both RPC and REST API types):
JSIGHT 0.3
URL /rpc-api
Protocol json-rpc-2.0
Method foo
Params
{
"input-1": 123 // some integer
}
Result
{
"output-1": 123, // some other integer
"output-2": "some string"
}
When you design your RPC API you can use as many such operations as you want.
So, what's the problem with this? Why do we need REST, if we already have RPC?
The problems are the following:
When you look at the method foo definition you do not have the slightest idea, what it does.
When you design RPC APIs you have absolute freedom, but freedom often can be a bad thing. Because people think in different fashions. You could think, that your API is easy and elegant, but other people would not think so.
Step 2. Standardized RPC
If you are an experienced API designer and you use the RPC style, you will try to follow some pattern to avoid the two faults mentioned above. For example, let's imagine, that your foo method returns a customer entity. Then you will never call it like foo, you will call it getCustomer, like this:
JSIGHT 0.3
URL /rpc-api
Protocol json-rpc-2.0
Method getCustomer
Params
{
"input-1": 123 // some integer
}
Result
{
"output-1": 123, // some other integer
"output-2": "some string"
}
Ok! Now when you just look at this description, you can say, that this method returns a customer; that parameter input-1 is some filter, most possibly, ID; and output-1 and output-2 are some customer properties.
Look, just using the standard way of naming the method, we made our API much more easy-to-understand.
Still, why do we need REST? What's the problem here?
The problem is, that when you have dozens of such RPC methods, your API looks messy. E. g.:
JSIGHT 0.3
URL /rpc-api
Protocol json-rpc-2.0
Method getCustomer
Method updateCustomer
Method getCustomerFriends
Method getCustomerFather
Method askCustomerConfirmation
# etc...
Why it is not easy to understand this bunch of methods? Because it is not the way our brain works. Our brain always groups actions by entity. You naturally think about an entity, and then about actions, you can do with it. E. g. what you can do with a cup? Take, hide, break, wash, turn over. And brain rarely thinks firstly about actions and then about entities. What can I take? Cup, ball, ice cream, ticket, wife. Not very natural.
So, what is REST about?
Step 3. REST
REST is about grouping entities and defining the most standard actions with these entities.
In IT we usually create, read, write, or delete entities. That's why we have POST, GET, PUT, and DELETE methods in HTTP, which is de facto the only implementation of the REST style.
When we group our methods by entities, our API becomes much clearer. Look:
JSIGHT 0.3
GET /customer/{id}
PUT /customer/{id}
GET /customer/{id}/friends
GET /customer/{id}/father
POST /customer/{id}/ask-confirmation
It is much easier to perceive now than in the RPC-style example above.
Conclusion
There are a lot of other issues, concerning differences between RPC and REST. REST has its faults as well as RPC. But I wanted to explain to you the main idea:
REST is a standard, that helps you to organize your API in a user-friendly fashion, that is comfortable for the human brain, so any developer can quickly capture your API structure.
RPC is just a way of calling remote operations.
All the examples above are gathered here: https://editor.jsight.io/r/g6XJwjV/1
I truly just don't understand what I'm missing
Not your fault, the literature sucks.
I think you may find Jim Webber's 2011 guidance enlightening.
Embrace HTTP as an application protocol. HTTP is not a transport protocol which happens to go conveniently through port 80. HTTP is an application protocol whose application domain is the transfer of documents over a network.
HTTP, like remote procedure calls, is a request/response protocol. The client sends a message to the server, the server sends a message back. Big deal.
But in the REST architectural style, we're also following the uniform interface constraint. That means (among other things) that everybody understands requests the same way, and everybody interprets responses the same way.
And that in turn means that general purpose components (browsers, web crawlers, proxies) can understand the request and response messages, and react intelligently to those messages, without needing to know anything at all about the specialization of a particular resource.
In the case of HTTP, we're passing messages about the domain of documents; if I want information from you, I ask for the latest copy of your document. If I want to send information to you, I send you a proposed modification to your document. Maybe you respond to my modification by creating a new document and you tell me to go look at that. And so on.
Useful business activity, then, becomes a side effect of manipulating these documents. Or, expressed another way, the document metaphor is the facade we present to the world.
And I've also read that functions like domain(.)com/login isn't restful b/c it's an action.
See above: the literature sucks.
Consider this resource identifier: https://www.merriam-webster.com/dictionary/login
Does it work like every other resource identifier on the web? Yes. The browser knows how to make a request to GET this resource, and when Merriam-Webster answers that the browser should instead look at https://www.merriam-webster.com/dictionary/log%20on then it fetches that resource as well.
The fact that "login"/"log on" are intransitive English verbs does not matter; it's an identifier, and that's all the browser needs to know.
Alternatively, consider this: URL shorteners work.
Resource identifiers are a lot like variable names in a computer program; so long as the identifier satisfies the production rules of your language, you can use anything you want. The machines don't care.
The key idea is that resources are not actions, they are "information that can be named". https://www.merriam-webster.com/dictionary/log%20on is the name of the document that describes Merriam-Webster's definition of the verb "log on".
Since the machines don't care what names we use, we can use the extra freedom that offers us to choose names that make life easier for people we care about.
I've read some folks say restful shouldn't be stateful and if it is, it's not restful. But aren't most restful endpoints using state via sessions?
Stateless communication is a REST architectural constraint.
each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server.
Cookies are one of the corners where HTTP failed to satisfy the stateless communication constraint.
I'm not going to let just anyone delete data w/o being logged in.
Not a problem: every HTTP request carries its own Authorization metadata; you aren't supposed to "remember" previous messages in the conversation. Instead, you verify the provided credentials every time.

Single endpoint instead of API - what are the disadvantages?

I have a service, which is exposed over HTTP. Most of traffic input gets into it via single HTTP GET endpoint, in which the payload is serialized and encrypted (RSA). The client system have common code, which ensures that the serialization and deserialization will succeed. One of the encoded parameters is the operation type, in my service there is a huge switch (almost 100 cases) that checks which operation is performed and executes the proper code.
case OPERATION_1: {
operation = new Operation1Class(basicRequestData, serviceInjected);
break;
}
case OPERATION_2: {
operation = new Operation2Class(basicRequestData, anotherServiceInjected);
break;
}
The endpoints have a few types, some of them are typical resource endpoints (GET_something, UPDATE_something), some of them are method based (VALIDATE_something, CHECK_something).
I am thinking about refactoring the API of the service so that it is more RESTful, especially in the resource-based part of the system. To do so I would probably split the endpoint into the proper endpoints (e.g. /resource/{id}/subresource) or RPC-like endpoints (/validateSomething). I feel it would be better, however I cannot make up any argument for this.
The question is: what are the advantages of the refactored solution, and what follows: what are the disadvantages of the current solution?
The current solution separates client from server, it's scalable (adding new endpoint requires adding new operation type in the common code) and quite clear, two clients use it in two different programming languages. I know that the API is marked as 0-maturity in the Richardson's model, however I cannot make up a reason why I should change it into level 3 (or at least level 2 - resources and methods).
Most of traffic input gets into it via single HTTP GET endpoint, in which the payload is serialized and encrypted (RSA)
This is potentially a problem here, because the HTTP specification is quite clear that GET requests with a payload are out of bounds.
A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.
It's probably worth taking some time to review this, because it seems that your existing implementation works, so what's the problem?
The problem here is interop - can processes controlled by other people communicate successfully with the processes that you control? The HTTP standard gives us shared semantics for our "self descriptive messages"; when you violate that standard, you lose interop with things that you don't directly control.
And that in turn means that you can't freely leverage the wide array of solutions that we already have in support of HTTP, because you've introduce this inconsistency in your case.
The appropriate HTTP method to use for what you are currently doing? POST
REST (aka Richardson Level 3) is the architectural style of the world wide web.
Your "everything is a message to a single resource" approach gives up many of the advantages that made the world wide web catastrophically successful.
The most obvious of these is caching. "Web scale" is possible in part because the standardized caching support greatly reduces the number of round trips we need to make. However, the grain of caching in HTTP is the resource -- everything keys off of the target-uri of a request. Thus, by having all information shared via a single target-uri, you lose fine grain caching control.
You also lose safe request semantics - with every message buried in a single method type, general purpose components can't distinguish between "effectively read only" messages and messages that request that the origin server modify its own resources. This in turn means that you lose pre-fetching, and automatic retry of safe requests when the network is unstable.
In all, you've taken a rather intelligent application protocol and crippled it, leaving yourself with a transport protocol.
That's not necessarily the wrong choice for your circumstances - SOAP is a thing, after all, and again, your service does seem to be working as is? which implies that you don't currently need the capabilities that you've given up.
It would make me a little bit suspicious, in the sense that if you don't need these things, why are you using HTTP rather than some messaging protocol?

What URL should be used to update a property of all members of a collection

I am wrapping a legacy CLI interface into a web service/interface (using JAX-RS) and using REST style as far as possible.
The service manages CRUD of a collection of entities, plus an additional, [de]activate action pair, which change the active state and property of the entity.
For an individual entity, I have implemented activate/deactivate as:
Content-Type: text/plain
PUT /entities/{identifier}/active
DATA "true"|"false"
RESPONSE 303 Location: /entity/{identifier}
However, the CLI also provides a useful operation to activate/deactivate all entities at once. This is effectively a global bulk update operation, as it (may) change the state of every entity in the collection.
I'm looking for suggestions on how best to express such global operations with URLs. I think there is no RESTful way to express them, but would be happy to be corrected. Are there any generally accepted or standard URL styles for this?
So far, for the global operations I am using this...
POST /entities/activate
POST /entities/deactivate
RESPONSE 204
... which I realize is not remotely RESTful, but at least has the benefit of being simple for a human client to understand and invoke. I'm looking for a better, and hopefully standard, approach to improve on this.
(I also considered using an /entities/all pseudo element, but decided it made things a bit more complicated on the server side with no benefit to clients.)
To recap:
I have a resource called entities which represents a collection.
Each member is an entity, identified by its {identifier}.
Each entity has a number of properties including a boolean state property: active.
Each entity can be activated and deactivated by invoking an operation.
For individual entities, I am exposing that operation via a POST (or PUT) on entities/{identifier}/active.
I think that much is reasonable.
There is another operation, which I want to expose, which activates/deactivates all members of the collection.
I am looking for a standard approach for expressing those two global operations, which change the state of all members of the collection, in a URL.
Update
Following Jon's suggestion, the activate/deactivate operation for all members of the entities collection shall become:
Content-Type: text/plain
PUT /entities/active
DATA "true"|"false"
RESPONSE 204
What thing does /entities/activate represent. How does that thing differ from /entities/deactivate? If I'm doing something that changes them (PUT) or acts upon them (POST) why can I not use the same resource to activate as to deactivate?
This doesn't seem to make much sense. It seems like you are using URIs to identify operations.
However, /entities/all at least has the advantage of using a single identifier for a single resource (there's nothing "pseudo" about it, it's no less real than any of the other resources you made up).
/entities/ would perhaps be better still. It's common, though certainly not required, and often useful (due to the ability to use common relative URI paths like ../) to have the identifier of a step up in the path component identify the total of a set of related entities.
So, have /entities/[some id]/ identify a given entity, and PUT something describing it as active or inactive to change that. Then have /entities/ represent all of them, and PUT something representing the fact that they are all active or all inactive to set them all as such.

Correct HTTP request method for nullipotent action that takes binary data

Consider a web API method that has no side effects, but which takes binary data as a parameter. An example would be a method that tells the user whether or not their image is photoshopped, but does not permanently store the image or the result on its servers.
Should such a method be a GET or a POST?
GET doesn't seem to have a recommended way of sending data outside of URL parameters, but the behavior of the method implies a GET, which according to the HTTP spec is for safe, stateless responses. This becomes particularly constraining under the semantics of REST, which imply that POST methods create a new object on the server.
This becomes particularly constraining under the semantics of REST, which imply that POST methods create a new object on the server.
While a POST request means that the entity sent will be treated "as a new subordinate of the resource identified by the Request-URI", there is no requirement that this result in the creation of a new permanent object or that any such new object be identified by a URI (so no new object as far as the client knows). An object can be transient, representing the results of e.g. "Providing a block of data, such as the result of submitting a form, to a data-handling process" and not persisting after the entity representing that object has been sent.
While this means that a POST can create a new resource, and is certainly the best way to do so when it is the server that will give that new resource its URI (with PUT being the more appropriate method when the client dictates the new URI) it is can also be used for cases that delete objects (though again if it's a deletion of a single* resource identifiable by a URI then DELETE is far more appropriate), both create and delete objects, change multiple objects, it can mean that your kitchen light turns on but that the response is the same whether that worked or failed because the communication from the webserver to the kitchen light doesn't allow for feedback about success. It really can do anything at all.
But, your instincts are good in wanting this to be a GET: While the looseness of POST means we can make a case for it for just about every request (as done by approaches that use HTTP for an RPC-like protocol, essentially treating HTTP as if it was a transport protocol), this is inelegant in theory, inefficient in practice and clumsy in definition. You have an idempotent function that depends on solely on what the client is interested in, and that maps most obviously the GET in a few ways.
If we could fit everything in a URI then GET would be easy. E.g we can define a simple integer addition with something like http://example.net/addInts?x=1;y=2 representing the addition of 71 and 2 and hence being a permanent immutable resource representing the number 3 (since the results of GET can vary with changes to a resource over time, but this resource never changes) and then use a mechanism like HTML's <form> or javascript to allow the server to inform the client as to how to construct the URIs for other numbers (to maintain the HATEOS and/or COD constraints). Simples!
Your problem here is that you do not have input that can be represented as concisely as the numbers 1 and 2 can above. In theory you could do something like http://example.net/photoshoppedCheck?image=data:image/png;base64,iVBORw0KGgoAAAANSU… and hence create a URI that represents the resource of the results of the check. This URI will though will have 4 characters for every 3 bytes in the image. While there's no absolute limit on URI length both the theory and the practice allow this to fail (in theory HTTP allows for proxies and servers to set a limit on URI length, and in practice they do).
An argument could be made for using GET and sending a request body the same way as you would with a POST, and some webservers will even allow you to do this. However, GET is defined as returning an entity describing the resource identified in the URI with headers restricting how that entity does that describing: Since the request body is not part of that definition it must be ignored by your code! If you were tempted to bend this rule then you must consider that:
Some webservers will refuse the request or strip the body, so you may not be able to.
If your webserver does allow it, the fact that its not specified means you can't be sure an upgrade won't "fix" this and so break your code.
Some proxies will refuse or strip the request.
Some client libraries will most certainly refuse to allow developers to send a request body along with a GET.
So it's a no-no in both theory and practice.
About the only other approach we could do apart from POST is to have a URI that we consider as representing an image that was not photoshopped. Hence if you GET that you get an entity describing the image (obviously it could be the actual image, though it could also be something else if we stretch the concept of content-negotiation) and then PUT will check the image and if its deemed to not be photoshopped it responds with the same image and a 200 or just a 204 while if it is deemed to be photoshopped it responds with a 400 because we've tried to PUT a photoshopped image as a resource that can only be a non-photoshopped image. Because we respond immediately, there's no race-condition with simultaneous requests.
Frankly, this would be darn-right horrible. While I think I've made a case for it by the letter of the specs, it's just nasty: REST is meant to help us design clear APIs, not obtuse APIs we can offer a too-clever-for-its-own-good justification of.
No, in all the way to go here is to POST the image to a fixed URI which then returns a simple entity describing the analysis.
It's perfectly justifiable as REST (the POST creates a transient object based on that image, and then responds with an entity describing that object, and then that object disappears again). It's straight-forward. It's about as efficient as it could be (we can't do any HTTP caching† but most of the network delay is going to be on the upload rather than the download anyway). It also fits into the general use-case of "process something" that POST was first invented for. (Remember that first there was HTTP, then REST described why it worked so well, and then HTTP was refined to better play to those strengths).
In all, while the classic mistake that moves a web application away from REST is to abuse POST into doing absolutely everything when GET, PUT and DELETE (and perhaps the WebDAV methods) would be superior, don't be afraid to use its power when those don't meet the bill, and don't think that the "new subordinate of the resource" has to mean a full long-lived resource.
*Note that a "single" resource here might be composed of several resources that may have their own URIs, so it can be easy to have a single DELETE that deletes multiple objects, but if deleting X deletes A, B & C then it better be obvious that you can't have A, B or C if you don't have X or your API is not going to be understandable. Generally this comes down to what is being modelled, and how obvious it is that one thing depends on another.
†Strictly speaking we can, as we're allowed to send cache headers indicating that sending an identical entity to the same URI will have the same results, but there's no general-purpose web-software that will do this and your custom client can just "remember" the opinion about a given image itself anyway.
It's a difficult one. Like with many other scenarios there is no absolutely correct way of doing it. You have to try to interpret RESTful principles in terms of the limitations of the semantics of HTTP. (Incidentally, I don't think it's right to think of REST having semantics, REST is an architectural style which is commonly used with HTTP services, but can be used for any type of interface.)
I've faced a similar situation in my current project. We chose to use a POST but with the response code being a 200 (OK) rather than the 201 (Resource Created) usually returned by RESTful Web APIs.

How should I deal with object hierarchies in a RESTful API?

I am currently designing the API for an existing PHP application, and to this end am investigating REST as a sensible architectural approach.
I believe I have a reasonable grasp of the key concepts, but I'm struggling to find anybody that has tackled object hierarchies and REST.
Here's the problem...
In the [application] business object hierarchy we have:
Users
L which have one-to-many Channel objects
L which have one-to-many Member objects
In the application itself we use a lazy load approach to populate the User object with arrays of these objects as required. I believe in OO terms this is object aggregation, but I have seen various naming inconsistencies and do not care to start a war about the precise naming convention </flame war>.
For now, consider I have some loosely coupled objects that I may / may not populate depending on application need.
From a REST perspective, I am trying to ascertain what the approach should be. Here is my current thinking (considering GET only for the time being):
Option 1 - fully populate the objects:
GET api.example.com/user/{user_id}
Read the User object (resource) and return the User object with all possible Channel and Member objects pre-loaded and encoded (JSON or XML).
PROS: reduces the number of objects, no traversal of object hierarchies required
CONS: objects must be fully populated (expensive)
Option 2 - populate the primary object and include links to the other object resources:
GET api.example.com/user/{user_id}
Read the User object (resource) and return the User object User data populated and two lists.
Each list references the appropriate (sub) resource i.e.
api.example.com/channel/{channel_id}
api.example.com/member/{member_id}
I think this is close to (or exactly) the implications of hypermedia - the client can get the other resources if it wants (as long as I tag them sensibly).
PROS: client can choose to load the subordinates or otherwise, better separation of the objects as REST resources
CONS: further trip required to get the secondary resources
Option 3 - enable recursive retrieves
GET api.example.com/user/{user_id}
Read the User object and include links to lists of the sub-objects i.e.
api.example.com/user/{user_id}/channels
api.example.com/user/{user_id}/members
the /channels call would return a list of channel resources in the form (as above):
api.example.com/channel/{channel_id}
PROS: primary resources expose where to go to get the subordinates but not what they are (more RESTful?), no requirement to get the subordinates up front, the subordinate list generators (/channels and /members) provide interfaces (method like) making the response more service like.
CONS: three calls now required to fully populate the object
Option 4 - (re)consider the object design for REST
I am re-using the [existing] application object hierarchy and trying to apply it to REST - or perhaps more directly, provide an API interface to it.
Perhaps the REST object hierarchy should be different, or perhaps the new RESTful thinking is exposing limitations of the existing object design.
Any thoughts on the above welcomed.
There's no reason not to combine these.
api.example.com/user/{user_id} – return a user representation
api.example.com/channel/{channel_id} – return a channel representation
api.example.com/user/{user_id}/channels – return a list of channel representations
api.example.com/user/{user_id}/channel_list – return a list of channel ids (or links to their full representations, using the above links)
When in doubt, think about how you would display the data to a human user without "API" concerns: a user wants both index pages ({user_id}/channel_list) and full views ({user_id}/channels).
Once you have that, just support JSON instead of (or in addition to) HTML as the representation format, and you have REST.
The best advice I can give is to try and avoid thinking about your REST api as exposing your objects. The resources you create should support the use cases you need. If necessary you might create resources for all three options:
api.example.com/completeuser/{id}
api.example.com/linkeduser/{id}
api.example.com/lightweightuser/{id}
Obviously my names are a bit goofy, but it really doesn't matter what you call them. The idea is that you use the REST api to present data in the most logical way for the particular usage scenario. If there are multiple scenarios, create multiple resources, if necessary. I like to think of my resources more like UI models rather than business entities.
I would recommend Restful Obects which is standards for exposing domain model's restful
The idea of Restful Objects is to provide a standard, generic RESTful interface for domain object models, exposing representations of their structure using JSON and enabling interactions with domain object instances using HTTP GET, POST, PUT and DELETE.
According to the standard, the URIs will be like:
api.example.com/object/user/31
api.example.com/object/user/31/properties/username
api.example.com/object/user/31/collections/channels
api.example.com/object/user/31/collections/members
api.example.com/object/user/31/actions/someFunction
api.example.com/object/user/31/actions/someFunction/invoke
There are also other resources
api.example.com/services
api.example.com/domain-types
The specification defines a few primary representations:
object (which represents any domain object or service)
list (of links to other objects)
property
collection
action
action result (typically containing either an object or a list, or just feedback messages)
and also a small number of secondary representations such as home, and user
This is interesting as you’ll see that representations are fully self-describing, opening up the possibility of generic viewers to be implemented if required.
Alternatively, the representations can be consumed directly by a bespoke application.
Here's my conclusions from many hours searching and with input from the responders here:
Where I have an object that is effectively a multi-part object, I need to treat that as a single resource. Thus if I GET the object, all the sub-ordinates should be present. This is required in order that the resource is cacheable. If I part load the object (and provide an ETag stamp) then other requestors may receive a partial object when they expected a full one. Conclude - objects should be fully populated if they are being made available as resources.
Associated object relationships should be made available as links to other (primary) resources. In this way the objects are discoverable by traversing the API.
Also, the object hierarchy that made sense for main application site may appear not be what you need to act in RESTful manner, but is more likely revealing problems with the existing hierarchy. Having said this the API may require more specialised use cases than had been previously envisaged, and specialised resources may be required.
Hope that helps someone