How to better specify kindo fo ID in RESTful service - rest

I'm looking for an opinion about defining contract for standard GET/PUT/POST/DELETE methods.
We have resource, let's say Client, so route will be /clients
However, we have two types of id for the client. One is the ID generated by our system. On top of that we want optionally allow customers use external id, generated by customer themselves.
So, if customer never going to add clients to the system, don't really interested about integration, and need only use method GET to read customer, endpoint will be:
/clients/{id}
However, if they want full integration, with ability to add clients, and use some their id, we want give them ability to use their own id.
We considered four possible solutions:
1. /clients/external/{externaId}
2. /clients/ext-{externalId}
3. /clients/{externalId}?use-external-id=true
4. /clients/{externalId} with additional header -"use-external-id": true
We are leaning to options 3 and 4 (can be supported simultaneously) but concerns about "restfulness" of such approach. Any opinions on this? What would you choose and why?

REST says nothing about URLs.
How different are internal and external clients? If the only difference is the existence of an externalId property, just use the /clients endpoint and add the property to your client resource. Always assign and use the internal id property in your API, but allow queries to filter by the customer-provided external id also.

How about this:
/clients/client_id/1 - for automatically generated ids
/clients/external_id/d23sa - for filtering on the external_id field
This could be extended to generically filter on any field of a resource and is the approach my company used in developing SlashDB.

Related

How should I design a REST API

I'm thinking about a REST API design. There are several tables in my database. For example Customer and Order.
Of course - each Order has its Customer (and every customer can have many Orders).
I've decided to provide such an interface
/api/v1/Customers/ -- get list of Customers, add new Customer
/api/v1/Customers/:id: -- get Customer with id=:id:
/api/v1/Orders/ -- get list of Orders, add new Order
/api/v1/Orders/:id: -- get Order with id=:id:
It works flawlessly. But my frontend has to display a list of orders with customer names. With this interface, I will have to make a single call to /api/v1/Orders/ and then another call to /api/v1/Customer/:id: for each record from the previous call. Or perform two calls to /api/v1/Orders/ and /api/v1/Customers/ and combine them on the frontend side.
It looks like overkill, this kind of operation should be done at the database level. But how can/should I provide an appropriate interface?
/api/v1/OrdersWithCustomers
/api/v1/OrdersWithCustomers/:id:
Seems weir. Is it a right way to go
There's no rule that says you cannot "extend" the data being returned from a REST API call. So instead of returning "just" the Order entity (as stored in the backend), you could of course return an OrderResponseDTO which includes all (revelant) fields of the Order entity - plus some from the Customer entity that might are relevant in your use case.
The data model for your REST API does not have to be an exact 1:1 match to your underlying database schema - it does give you the freedom to leave out some fields, or add some additional information that the consumers of your API will find helpful.
Great question, and any API design will tend to hit pragmatic reality at some point like this.
One option is to include a larger object graph for each resource (ie include the customer linked to each order) but use filter query parameters to allow users to specify what properties they require or don't require.
Personally I think that request parameters on a restful GET are fine for either search semantics when retrieving a list of resources, or filtering what is presented for each resource as in this case
Another option for your use case might be to look into a GraphQL approach.
How would you do it on the web?
You've got a web site, and that website serves documents about Customers, and documents about Orders. But your clients aren't happy, because its too much boring, mistake-prone work to aggregate information in the two kinds of documents.
Can we please have a document, they ask, with the boring work already done?
And so you generate a bunch of these new reports, and stick them on your web server, and create links to make it easier to navigate between related documents. TA-DA.
A "REST-API" is a facade that makes your information look and act like a web site. The fact that you are generating your representations from a database is an implementation details, deliberately hidden behind the "uniform interface".

REST API: Resource hierarchy and multiple URI

I work with a banking database, which is structured like this:
Table Primary Key Unique Keys Foreign Keys
-------------------------------------------------------------
BANK ID BIC
CUSTOMER ID CUSTNO, PASS, CARD BANK
ACCOUNT ID IBAN BANK, CUSTOMER
I want to design a clean REST API, but I run into following problems:
Should I put resources in a hierarchy, or rather flat? The problem with the hierarchy might be that the client only knows the ACCOUNT ID, but does not know the CUSTOMER ID, so how is he supposed to get the resource?
/banks/{id}/customers/{id}/accounts{id}
or
/banks/{id}
/customers/{id}
/accounts{id}
The primary key in each table is the database ID. It is an internal ID and has no business meaning. Is it correct to use it as the default URI of the resource?
Each object has its own set of unique keys. For example, CUSTOMER can be identified by his CUSTNO, PASS or CARD. Each client only has a subset of these keys. Should I define a sub-resource per key or provide a lookup service that will give the proper URI back?
/customers/id/{id}
/customers/custno/{custno}
/customers/pass/{pass}
/customers/card/{card}
or
/lookup/customer?keyType=card&keyValue=AB-303555
(gives back customer {id})
I am asking what is the truly RESTful way, what is best practice. I haven't found proper answers yet.
I am asking what is the truly RESTful way, what is best practice.
REST doesn't care what spellings you use for your identifiers.
/ef726381-dd43-4017-9778-83cee2bbbd93
is a perfectly RESTful URI, suitable for any use case.
Outside of some purely mechanical concerns, general purpose consumers treat a URI as a single opaque unit. There's no notion of a consumer extracting semantic information from the URI -- which means that any information encoded into the identifier is done at the server's discretion and for its use alone.
For cases where information known to the client needs to be included in the target-uri of the request, we have URI Templates, which are a sort of generalization of a GET form in HTML. So a way to think about your problem is to consider what information the client has, and how they would put that information into a form.
HTML's form processing rules are pretty limiting -- general URI templates have fewer constraints.
/customers/id/{id}
/customers/custno/{custno}
/customers/pass/{pass}
/customers/card/{card}
Having multiple resources sharing common information is normal in REST -- your resource model is not your data model. So this could be fine. It's even OK to have multiple resources that share representations. You could have them stand alone, or you could have them share a Content-Location, or a canonical link relation, or you could simply have those resources redirect to the canonical resource.
It's all good.
So you mean if a UUID can be a valid URI, then a table autonumber key can be too?
Yes, exactly.
Note that if you want the lifetime of the URI to extend beyond the lifetime of your current implementation, then you need to design your identifiers with that constraint in mind. See Cool URIs Don't Change.
The clients don't care what the URI is, they just want the link to work again when they need it.

Good URL syntax for a GET request with a composite key

Let's take the following resource in my REST API:
GET `http://api/v1/user/users/{id}`
In normal circumstances I would use this like so:
GET `http://api/v1/user/users/aabc`
Where aabc is the user id.
There are times, however, when I have had to design my REST API in a way that some extra information is passed with the ID. For example:
GET `http://api/v1/user/users/customer:1`
Where customer:1 denotes I am using an id from the customer domain to lookup the user and that id is 1.
I now have a scenario where the identifier is more than one key (a composite key). For example:
GET `http://api/v1/user/users/customer:1;type:agent`
My question: in the above URL, what should I use as the separator between customer:1 and type:agent?
According to https://www.ietf.org/rfc/rfc3986.txt I believe that the semi-colon is not allowed.
You should either:
Use parameters:
GET http://api/v1/user/users?customer=1
Or use a new URL:
GET http://api/v1/user/users/customer/1
But use Standards like this
("Paths tend to be cached, parameters tend to not be, as a general rule.")
Instead of trying to create a general structure for accessing records via multiple keys at once, I would suggest trying to think of this on more of a case-by-case basis.
To take your example, one way to interpret it is that you have multiple customers, and those customers each may have multiple user accounts. A natural hierarchy for this would be:
/customer/x/user/y
Often an elegant decision like this can be made, that not only solves the problem but also documents your data-model in a way that someone can easily see that users belong to customers via a 1-to-many relationship.

REST Resources, should they be client specific, server specific or both?

I have a use case where for a same entity, there are 2 identifiers, and each of them can map to the entity if used separately. 1 identifier is client friendly (say c_id), and the other is server friendly (say s_id). Clients do know the s_id, but in most cases they wont use it. And server knows both the ids, but the implementation on server is such that every thing is easily mapped using s_id.
In such a case, is it a good practice to provide resources on both c_id & s_id level, where the resource name and id (in input) will differ and will do the same thing, or should it be only a single resource, which also leads to the debate that which resource should be used.
I would normally have the resources existing under their server identities, and then provide search methods that return 302 redirects (or 307 if you prefer) to the appropriate resources. The clients would use these search/query methods to arrive at the correct resources.
Because the server "owns" the resources (and their URLs), it's fine for it to arrive at the resources by URL-fiddling. Whereas, because the clients shouldn't engage in URL-fiddling to find resources, giving them a query method where they can specify the ID(s) they know as query string parameters feels cleaner.
Your API exists for the benefit of its users. You should always strive to make it as easy as possible for them. If unique client-friendly IDs exist for all resources, then make your API work against the client-friendly ID. Your API can store a map from clientId to serverId in memory and easily switch to the ID it's more comfortable with.
If there aren't unique client-friendly IDs for all resources, you've got a pickle. I'd start by trying to close the gap (ie give the remaining resources clientIds). If that's not an option, then I agree with Damien.
What I often do is create the canonical URI as the one with the s_id, so something like,
http://example.org/api/foo/{s_id}
and then provide a search facility that allows searching by c_id, and potentially other attributes.
http://examples.org/api/foos?c_id={c_id}
This can return a list of foos, each with a link to the s_id URI. Or if, as in your case, only one foo returns, then you could either redirect to the canonical URI, or you can actually return the full foo representation and set the Content-Location header to the canonical URI.

RESTful url to GET resource by different fields

Simple question I'm having trouble finding an answer to..
If I have a REST web service, and my design is not using url parameters, how can I specify two different keys to return the same resource by?
Example
I want (and have already implemented)
/Person/{ID}
which returns a person as expected.
Now I also want
/Person/{Name}
which returns a person by name.
Is this the correct RESTful format? Or is it something like:
/Person/Name/{Name}
You should only use one URI to refer to a single resource. Having multiple URIs will only cause confusion. In your example, confusion would arise due to two people having the same name. Which person resource are they referring to then?
That said, you can have multiple URIs refer to a single resource, but for anything other than the "true" URI you should simply redirect the client to the right place using a status code of 301 - Moved Permanently.
Personally, I would never implement a multi-ID scheme or redirection to support it. Pick a single identification scheme and stick with it. The users of your API will thank you.
What you really need to build is a query API, so focus on how you would implement something like a /personFinder resource which could take a name as a parameter and return potentially multiple matching /person/{ID} URIs in the response.
I guess technically you could have both URI's point to the same resource (perhaps with one of them as the canonical resource) but I think you wouldn't want to do this from an implementation perspective. What if there is an overlap between IDs and names?
It sure does seem like a good place to use query parameters, but if you insist on not doing so, perhaps you could do
person/{ID}
and
personByName/{Name}
I generally agree with this answer that for clarity and consistency it'd be best to avoid multiple ids pointing to the same entity.
Sometimes however, such a situation arises naturally. An example I work with is Polish companies, which can be identified by their tax id ('NIP' number) or by their national business registry id ('KRS' number).
In such case, I think one should first add the secondary id as a criterion to the search endpoint. Thus users will be able to "translate" between secondary id and primary id.
However, if users still keep insisting on being able to retrieve an entity directly by the secondary id (as we experienced), one other possibility is to provide a "secret" URL, not described in the documentation, performing such an operation. This can be given to users who made the effort to ask for it, and the potential ambiguity and confusion is then on them, if they decide to use it, not on everyone reading the documentation.
In terms of ambiguity and confusion for the API maintainer, I think this can be kept reasonably minimal with a helper function to immediately detect and translate the secondary id to primary id at the beginning of each relevant API endpoint.
It obviously matters much less than normal what scheme is chosen for the secret URL.