I have a resource with identifier id and attribute name - name is unique for each of the resource instances.
In order to get, patch and delete the resource, is it REST and JSON:API compliant to use the name field
as the identifier in the URL?
e.g. to get resource by name, is the following URL compliant:
GET /resource/{name}
or is the following to be used / preferable:
GET /resource?name={name}
to patch or delete by name, can one use:
PATCH /resource/{name}
DELETE /resource/{name}
In order to get, patch and delete the resource, is it REST and JSON:API compliant to use the name field as the identifier in the URL?
Yes. REST doesn't care what spellings you use for your resource identifiers, as long as those identifiers are consistent with the production rules defined in RFC 3986.
That might mean that you need to encode the attribute name - for instance, replacing some reserved characters with the equivalent hex representation.
GET /resource/{name}
PATCH /resource/{name}
DELETE /resource/{name}
That's fine
GET /resource?name={name}
PATCH /resource?name={name}
DELETE /resource?name={name}
Also fine. It's a trade off; encoding information into path segments mean that you can take advantage of relative references and dot segments. Using key value pairs in the query part means that you can use HTML forms to allow the client to specify a name.
GET /resource?name={name}
DELETE /resource/{name}
Technically, you can play mix-and-match, but general purpose caches aren't going to know that you are being clever, and will not invalidate cached entries when the URI are different.
This answer fully ignores that it should be also compliant with JSON API specification.
That's fair comment.
The JSON:API specification does not introduce any significant constraints on the spelling conventions used in URI.
It does, however, expect that identifiers can be extended with application/x-www-form-urlencoded key value pairs to support sorting, pagination, filtering and so on.
(Warning: please be careful when reading the JSON:API specification, as the use of "resource" there does not align particularly well with the meaning of resource in the context of REST.)
The JSON:API recommendations for URI design encourage the use of path segments for referencing "resources" as though they were individually addressable hierarchically organized elements of a single "reference document".
Furthermore, the recommendations call for using a specific hierarchical spelling, using the type and identifier of a resource to compute its URI
/{type}/{id}
In other words, GET /resource/{name} should return a application/vnd.api+json representation with a type member resource and an id member name. The specification applies the additional constraint that this (type, id) combination must be unique.
If name is just a property, and not actually the identifier, then JSON:API recommends that you treat it as a filter
/resource?filter%5Bname%5D=abcde
And the representation returned would include a self link relation that tracks with the identifier in the usual way.
(Note: [] are RFC 3986 gen-delims, and therefore require hex encoding in the query part. At least one of the JSON:API examples includes a note explain this, but filtering example in recommendations does not emphasize this. In practice? you might get away with using them unencoded -- the use of square brackets in the query part was a common non-compliant convention).
Related
Years ago I created a tiny web service that serves the same resource in two representations.
# returns a collection of Foos
GET /foo
# returns the same collection of Foos in a different JSON representation
GET /foo?projection=X with 'Accept: my-specific-media-type'
This works quite well in (Java) code as I can have two methods mapped to the same #Path both with different return types. One accepts a #QueryParam and #Consumes a specific media type while the other doesn't.
However, according to the (current) #ApiOperation Swagger annotation I opted for the wrong API design.
A combination of a HTTP method and a path creates a unique operation
Hence, after I upgraded my old project to current library versions the Swagger model only contains a single GET /foo operation - which one is random as it depends on runtime code introspection through Java reflections.
So, the question is this: is the Foo resource in a different representation effectively the "same" resource or is it a different resource? The Swagger annotation seems to hint at the latter (different resource -> different path).
Part of the problem that you are running into is a mix of REST concepts and Swagger/OpenAPI concepts.
Resource is a REST concept: "any concept that might be the target of an author's hypertext reference must fit within the definition of a resource"
Representation is a REST concept: "A representation is a sequence of bytes, plus representation metadata to describe those bytes."
Operations are an OpenAPI concept: "OpenAPI defines a unique operation as a combination of a path and an HTTP method."
There's a certain amount of tension here because the viewpoints aren't actually in alignment with each other.
For example, from the perspective of REST, there's no reason to document a "GET operation", because GET is part of the uniform interface - it has the same semantics no matter what value is used as the target-uri. That's a part of a key architectural constraint that makes the world wide web possible - consistent semantics means that we can use general purpose components (like web browsers) to interact with all of the different resources on the web.
is the Foo resource in a different representation effectively the "same" resource or is it a different resource?
"It depends".
A classic example of "one resource, different representations" would be a picture, where we might have a GIF, JPEG, PNG, BMP. Same picture (ish), but different sequences of bytes that need to be processed in different ways.
Similarly, you might have a web page (HTML), and also a text/plain representation, or a JSON representation, etc.
One of the important questions to ask: is a general purpose cache going to have the information necessary to return the "correct" representation for a request?
That said: given that your original design was using a query parameter to distinguish one projection from another, you should likely respect that instinct and continue to treat the different representations as belonging to different resources (meaning that general purpose caches will keep them completely separate).
Whether that means that you want to share the same path /foo (treating projection as an optional #ApiParam), or give each projection a different path (defining separate operations for each unique path) is less clear. In a brownfield project, my bias would be toward documenting what you already have, rather than making a bunch of breaking changes.
But it is certainly reasonable to treat "easy to document" as a design constraint.
So, the question is this: is the Foo resource in a different representation effectively the "same" resource or is it a different resource?
Fielding defined a resource as such:
The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource. A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time.
More precisely, a resource R is a temporally varying membership function MR(t), which for time t maps to a set of entities, or values, which are equivalent. The values in the set may be resource representations and/or resource identifiers. A resource can map to the empty set, which allows references to be made to a concept before any realization of that concept exists -- a notion that was foreign to most hypertext systems prior to the Web [61]. Some resources are static in the sense that, when examined at any time after their creation, they always correspond to the same value set. Others have a high degree of variance in their value over time. The only thing that is required to be static for a resource is the semantics of the mapping, since the semantics is what distinguishes one resource from another.
...
REST uses a resource identifier to identify the particular resource involved in an interaction between components. REST connectors provide a generic interface for accessing and manipulating the value set of a resource, regardless of how the membership function is defined or the type of software that is handling the request. The naming authority that assigned the resource identifier, making it possible to reference the resource, is responsible for maintaining the semantic validity of the mapping over time (i.e., ensuring that the membership function does not change). (Source)
In short, a resource is something that you give a name in order to reference it later on. This resource is a container for data. That data can be represented in plenty of ways. A representation is a concrete instance of the resource' data with respect to the media-type the representation was created for. The media-type itself defines the syntax and semantic of a concrete instance. I.e. HTML defines which attributes and elements are admissible within the payload and what these things express.
As REST shouldn't have typed "resources" meaningful to clients content type negotiation should be used. Here a client express its capabilities via the Accept header to the server and the server will chose a representation format that will suite the data the best. A well-behaved server will only chose among the suggested media types as it knows the client can handle the data. A non-well-behaved client will just ignore the header and send whatever it wants which eventually may prevent clients from being able to process the payload at all.
REST is all about decoupling of clients from servers and allowing the server side from evolving in future without breaking clients. This however is only possible if both use some kind of indirection. I.e. not the URI itself is the relevant thing in a payload but the link-relations that are attached to that URI. A link relation might be something like next, prev, first or last for a traversable collection or something like prefetch witch just states that the content of the annotated URI may be loaded once the client has loaded all other things and is currently IDLE as this content may be requested next with some likelihood. Such link relations are either standardized or should follow the extension mechanism defined in Web Linking.
In regards to your actual question. Think of an arbitrary product ABC1234. This product contains some properties such as its price, the current number of items in stock, some metadata describing the product and what not. These properties might be expressed in JSON, in XML or in HTML. Clients which are able to process these media-types will be able to create an "object" with the same properties with hardly any issues. The actual representation format used shouldn't have an influence on the actual data of the resource itself. After all, the representation format is just a mutually agreed way of exchanging the data between client and server in order to allow the recipient of the payload to process it in the same way the sender intended it initially.
As Fielding mentioned before, such a resource may be static or change over time. With the product example from above, the price may change over time, though this doesn't change the semantics of the actual product. Over time sometimes the same data that is present for a resource need to be made available as part of an other resource. This is totally fine and here things start to get a bit more interesting. As part of a company merger one of our clients needed to expose all of their items with different names. In their case they opted for providing both product names for a year simultaneously. By definition these would be two different resources to an arbitrary HTTP client, i.e ABC1234 and XYZ12345 even though they "represent" the data of the same real-live product. They could also have opted for using (permanent) redirection of clients to the "new" URI and therefore hint clients that the product is actually the same.
The resource per name (or URI) concept is also noticable if you take a look at how caching works in the HTTP ecosystem. Here the effective request URI is used as cache-key in order to look up whether for the requested URI already a stored response is present. Any unsafe operation performed on that URI will lead to an eviction of that stored response. This is i.e. one of the reasons why HTTP isn't meant for batch-operations as these may bypass the cache at all and lead to wrong and/or misleading results.
Years ago I created a tiny web service that serves the same resource in two representations.
GET /foo # returns a collection of Foos
GET /foo?projection=X # returns a collection of Foos in a different coordinate system i.e. different representation
According to how HTTP defines effective request URIs these two URIs would target two different resources actually, event though they express the same data just with different representations. A probably better approach would have been to expose just /foo and use either specialized media-types for the different coordinate systems or even better a media-type that supports profiles and hint the recipients processor via the profile attribute which "kind of" data it receives. Link relations, as mentioned above, also define a profile relation name that can be used to allow a client to chose between the URI returning "metric" or "imperial", "Kelvin", "Fahrenheit" or "Celsius" or similar measurement figures or the like.
So, long story short, loosely speeking the absolut URI, including matrix, query and path parameters, is what "names" a resource at an arbitrary client. The whole URI is the identifier of that resource after all. Slightly different names might result in local or intermediary cache misses and therefore indicate a different resource, even though the data expressed is the same as before. Instead of using two slighly different URIs redirection directives, content type negotiation or profiles on the same resource can be used to "get rid" of the sibling "resource" that only differ in different representation formats returned.
Let's say I have this URI endpoint:
:GET /v1/permissions
Which select all of the permissions on version 1.
One also can request this:
:GET /permissions
Which will request all permissions by the latest default version.
Now I want to select all of the permissions from a specific user.
I want to know what is the proper and respectable way to send the identifier of the user - in the URI endpoint OR in the http request headers OR as a GET param.
For example:
Method 1:
:GET /v1/groups/:id/permissions
Method 1.1:
:GET /v1/:id/permissions
Method 2:
:GET /v1/permissions,
"If-Match": "[REPLACE_ID_HERE]" (header)
Method 3:
:GET /v1/permissions/?groups=REPLACE_ID_HERE
All of them will work.
But which is the proper way?
But which is the proper way?
It's a common misconception.
The REST architectural style doesn't enforce any URI design (see notes below). It's totally up to you to pick the URIs that better identify your resources.
The URI syntax is defined in the RFC 3986. As general rule, the path is organized in hierarchical form (with segments separated by /) and can contain non-hierarchical data in the query component (starting with ?).
These approaches seem to be fine to identify the permissions of a particular group:
/v1/groups/:id/permissions
/v1/permissions?groups=id
The "right" approach would depend on your needs and how you model your API. In the first approach, the hierarchy expresses that the permissions belong to a particular group (the permissions depend on a group to exist). The second approach is more like filtering a collection of permissions by group.
Note 1: The REST architectural style is described in the chapter 5 of Roy T. Fielding's dissertation and it defines a set of constraints that must be followed by the applications that follow such architecture. However it says nothing about what the URIs must be like.
Note 2: The examples of a popular article written by Martin Fowler explaining a model defined by Leonard Richardson suggest a URI structure that looks friendly and easy to read.
Two points upfront:
There is no official REST specification issued by a central authority. The entire paradigm originates from a rather slim (yet ingenious) technical outline written by Roy Fielding in the year 2000.
However, there are several good books on the matter and hundreds of thousands of implementations that have led to a firm industry standard.
One of those standards is that REST Urls are specific to resources and ids embedded in those Urls reference resources of the same type. Thus GET /groups/:groupdId is orthodox (a standard implementation that matches the expectations of most programmers) whereas GET /groups/:permissionId is not.
Coming back to the 4 alternatives you contemplate:
Method 1:
:GET /v1/groups/:id/permissions
Is orthodox, since the resource managed by the endpoint is of type Group and :id is a Group id.
Method 1.1:
:GET /v1/:id/permissions
Is unorthodox since there is no indication of what resource type the Url refers to.
Method 2:
:GET /v1/permissions,
"If-Match": "[REPLACE_ID_HERE]" (header)
Is unorthodox, since resource ids are expected to be passed as part of the Url.
Method 3:
:GET /v1/permissions/?groups=REPLACE_ID_HERE
Is orthodox, since here the resource is Permission and the groupId is applied as a filter, for which request parameters are the adequate means.
The most common way of designing a REST API is following the resources (and - or sub-resources) structure. i.e. api url will start with your resource name followed by a unique ID for the resource in case of Single resource GET, PUT(update) or DELETE.
Ex :
1. /users/$unique_user_id - HTTP GET - Fetches the single user detail.
/users/$unique_user_id - HTTP PUT - updates the user details identified by the id with the related data.
/users/$unique_user_id - HTTP DELETE - Deletes the user identified by the ID.
If your case handles a well established relation between 2 resources you can handle them as sub-resources of the parent.
Ex :
/users/$user_id/permissions
/groups/$group_id/permissions
This model will suit if you won’t get a requirement to fetch permissions for multiple resources(kind of filtering)
Ex :
/permissions?group_ids=1,2,3
/permissions?user_ids=4,5,6
As per REST spec, you first need to determine what is the base resource you are requesting for. The name of the resource comes first in the URI. In your case, it's the Permission. Hence the URI will begin with permission, with an optional version prefix (as the whole API is versioned)
Following the resource name, you need to mention either a specific resource or a query parameters to get a broad list. Now here you have two options, based on what you are retrieving.
1) permission for a person: In this case, you need to put query param as the api itself won't be able to guess what is the id for. Hence it will be permissions/?personId=123
2) permission detail of a particular permission: Used when you have a list of permissions pre fetched, maybe as result of above api. In this case the identifier will belong to the resource itself, hence it will be specified as the resource identifier as permissions/5e55 where 5e55 is the primary key of the specified permission of whom detail is being sought after.
The major complexity in such design is properly identify the resource primary identifier and secondary identifier...
The primary identifier is put directly in type 2 and secondary is specified as query param.
All said, technically nothing will stop the either request style from working as long as you provide the parsing logic of the URI. REST just says that URI should be able to identify resource properly and does not impose an implementation requirement.
Consider a need to create a GET endpoint for fetching Member details using either of 4 options (It's common in legacy application with RPC calls)
Get member by ID
Get member by SSN
Get member by a combination of Phone and LastName (both must be passed)
What's a recommended strategy to live the REST spirit and yet provide this flexibility?
Some options I could think of are:
Parameters Based
/user/{ID}
/user?ssn=?
/user?phone=?&lname=?
Separate Endpoints
/user/{ID}
/user/SSN/{SSNID}
/user/{lname}/{phone}
RPC for custom
/user/{ID}
/user/findBySSN/
/user/findbycontact/
REST doesn't care what spelling you use for your identifiers.
For example, think about how you would do this on the web. You would provide forms, one for each set of search criteria. The consumer would choose which form to use, and submit the form, without ever knowing what the URI is.
In the case of HTML forms, there are specific processing rules for describing how the form information will be copied into the URI. The form takes on the aspect of a URI Template.
A URI Template provides both a structural description of a URI space and, when variable values are provided, machine-readable instructions on how to construct a URI corresponding to those values.
But there aren't any rules saying that restrict the server from providing a URI template that directs the client to copy the variable values into path segments rather than into the query string.
In other words, in REST, the server retains control of its own URI space.
You might sometimes prefer to use path segments because of their hierarchical nature, which may be convenient if you want the client to use relative resolution of relative references in your representations.
REST ≠ pretty URLs. The two are orthogonal.
Your question is about the latter, I feel.
Whilst the other answers have been good, if you want your API to work with HTML forms, go with query parameters on the collection /user resource for all fields, even for ID (assuming a human is typing these in based on information they are getting from sheets of paper on their desk, etc.)
If your server is able to produce links to each record, always produce canonical links such as /users/{id}, don't duplicate data under different URLs.
I have many resources like product, bookings and etc. Need routes to get all resources by user.
For example:
{GET} /bookings/user
I think this is incorrect, because this route would return user resource. Or I am wrong?
What is the right way?
I think this is incorrect, because this route would return user resource. Or I am wrong?
It returns a representation of the resource identified by /bookings/user. What resource is that? It's up to the origin server.
rest doesn't care what spelling conventions you use for your identifiers. As far as REST is concerned, /6414b60b-1ecb-4e28-8887-4bfe120810e7 is a perfectly satisfactory resource identifier.
If you want human readable identifiers, that's OK too. RFC 3986 encourages that practice:
A URI often has to be remembered by people, and it is easier for people to remember a URI when it consists of meaningful or familiar components.
You should also keep in mind that RFC 3986 distinguishes hierarchical and non-hierarchical signal in the URI
The URI syntax is organized hierarchically, with components listed in order of decreasing significance from left to right. -- section 1.2.3
The path component contains data, usually organized in hierarchical form, that, along with data in the non-hierarchical query component -- section 3.3
The query component contains non-hierarchical data that, along with data in the path component (Section 3.3), serves to identify a resource within the scope of the URI's scheme and naming authority (if any) -- section 3.4
In short, if you are describing information that is described in a hierarchy, then using path segments makes a lot of sense
I don`t return users and user ids, need return all booking for authorized user.
That sounds like you are describing a spelling like /my/bookings.
A heuristic that may help in URI design is to consider the benefits of relative references; much as with a file system, you can use dot-segments to navigate toward the root of the namespace.
`/my/bookings` + `../profile` --> `/my/profile`
There are reasons where you might not want to support hackable URI; so you'll want to think about that constraint, and its implications, carefully.
Typically, one would use a query parameter for this:
GET /bookings?userId={userId}
That would return all the bookings for the given user id.
I understand that for partial updates, an action must be taken that is not idempotent. To that end, a valid approach is to make a POST request to that resource.
I have a question though about related resources. For example imagine the following resources with their properties:
Accounts
Id
Name
Account #
Users (a collection)
Users
Id
Name
Now imagine I want to make a partial update to an Account - for example, to change the Account's name.
I could make the following request as a valid partial update:
POST /account/id/123
{
"name" : "My New Name"
}
My question is regarding a full PUT request which must be idempotent and must include a full representation of the resource.
Could I do the following as a valid idempotent request?
PUT /account/id/123
{
"name" : "My New Name",
"accountNumber" : "654-345-4323"
}
Is that considered a valid, idempotent action? I've included all the top level "Account" information, but I question it because I didn't post all the USERS that belong to the account as well.
In order to be a valid idempotent request, would I need to include all of it's sub resources as well in the PUT request?
An easier way to understand is to consider that the PUT method ignores the current state of the target resource, so a "full resource representation" means that it must have all data needed to replace the existent resource with a new one.
In your example, that could be a valid full representation for an account with no users.
It's fine for the server to assume default values when something is missing, but that should be documented properly as some users might confuse with a partial update.
If you want to design the PUT request as the full resource replacement, then this means that you need also to assign values to all the assignable (editable) properties of a resource, including the relations (links) of a resource. Otherwise, the properties which are not set are considered as being set to null.
For partial requests, you can use PATCH HTTP method. There is also a convention of PUT if your resource representation is simple enough to allow that, that you can use partial updates.
PATCH vs. PUT
Quoting:
PATCH vs. PUT
The HTTP RFC specifies that PUT must take a full new resource
representation as the request entity. This means that if for example
only certain attributes are provided, those should be remove (i.e. set
to null).
An additional method called PATCH has been proposed recently. The
semantics of this call are like PUT inthat it updates a resource, but
unlike PUT, it applies a delta rather than replacing the entire
resource. At the time of writing, PATCH was still a proposed standard
waiting final approval.
For simple resource representations, the difference is often not
important, and many APIs simply implement PUT as a synonym for PATCH.
This usually doesn’t give any problems because it is not very common
that you need to set an attribute to null, and if you need to, you can
always explicitly include it.
However for more complex representations, especially including lists,
it becomes very important to be able to express accurately the changes
you want to make. Therefore, it is my recommendation now to both
provide PATCH and PUT, and make PATCH do an relative update and have
PUT replace the entire resource.
It is important to realize that the request entity to PATCH is of a
different content-type that the entity that it is modifying. Instead
of being a full resource, it is a resource that describes
modifications to be made to a resource. For a JSON data model, which
is what this essay is advocating, I believe that there are two
sensible ways to define the patch format.
An informal approach where you accept a dict with a partial
representation of the object. Only attributes that are present are
updated. Attributes that are not present are left alone. This approach
is simple, but it has the drawback that if the resource has a complex
internal structure e.g. containing a big list of dicts, then that
entire list of dicts need to be given in the entity. Effectively PATCH
becomes similar to PUT again.
A more formal approach would be to
accept a list of modifications. Each modification can be a dict
specifying the JSON path of the node to modify, the modification
(‘add’, ‘remove’, ‘change’) and the new value.