Steve Webb Steve Webb - 10 days ago 6x
reST (reStructuredText) Question

Rest API: path for accessing derived data

It is not clear to me that if I have a micro service that is in place to provide some derived data how the rest api should be designed for this. For instance :-

If I have a customer and I want to access the customer I would define the API as:


this would return everything we know about the customer

however if I want to provide a microservice that simply tells me if the customer was previously known to the system with another account number what do I do. I want this logic to be in the microservice but how do I define the API



Both don't seem correct. In the first case it implies


could be used to get all the customer information but the microservice doesn't offer this.


Adding some extra details for clarification.

I suppose my issue is, I don't really want a massive service which handles everything customer related. It would be better if there were lighter weight services that handles customer orders, customer info, customer history, customer status (live, lost, dead....).

It strikes me all of these would start with


so would all the services be expected to provide a customer object back if only customer/XXXX was given with no extra in the path such as /orders

Also some of the data as mentioned isn't actually persisted anywhere it is derived and I want the logic of this hidden in a service and not in the calling code. So how is this requested and returned.


Doing microservices doesn't mean to have a separate artifact for each method. The rules of coupling and cohesion also apply to the microservices world. So if you can query several data all related to a customer, the related resources should probably belong to the same service.

So your resource would be /customers/{id}/previous-customer-numbers whereas /customers (plural!) is the list of customers, /customers/{id} is a single customer and /customers/{id}/previous-customer-numbers the list of customer numbers the customer previously had.

Try to think in resources, not operations. So returning the list of previously used customer numbers is better than returning just a boolean value. /customer/{id}/previous-accounts would be even better, I think...

Back to topic: If the value of previous-accounts is directly derived from the same data, i.e. you don't need to query a second database, etc. I would even recommend just adding the value to the customer representation:

    "id": "1234",
    "firstName": "John",
    "lastName": "Doe",
    "previouslyKnown": true,
    "previousAccounts": [
            "id": "987",

Whether the data is stored or derived shouldn't matter so the service client to it should not be visible on the boundary.

Adding another resource or even another service is unnecessary complexity and complexity kills you in the long run.

You mention other examples:

customer orders, customer info, customer history, customer status (live, lost, dead....)

Orders is clearly different from customer data so it should reside in a separate service. An order typically also has an order id which is globally unique. So there is the resource /orders/{orderId}. Retrieving orders by customer id is also possible:


which reads give me the list of orders for which the customer is identified by the given customer id.

These parameters which filter a list-like rest resource are called matrix parameters. You can also use a query parameter: /orders?customer={customerId} This is also quite common but a matrix parameter has the advantage that it clearly belongs to a specific part of the URL. Consider the following:


This would return the list of notifications belonging to the orders of the customer with the id 1234.

With a query parameter it would look like this:


It is not clear from the URL that the orders are filtered and not the notifications.

The drawback is that framework support for matrix parameters is varying. Some support them, some don't.

I'd like matrix parameters best here but a query parameter is OK, too.

Going back to your list:

customer orders, customer info, customer history, customer status (live, lost, dead....)

Customer info and customer status most likely belong to the same service (customer core data or the like) or even the same resource. Customer history can also go there. I would place it there as long as there isn't a reason to think of it separately. Maybe customer history is such a complicated domain (and it surely can be) that it's worth a separate service: /customer-history/{id} or maybe just /customer/{id}.

It's no problem that different services use the same paths for providing different information about one customer. They are different services and they have different endpoints so there is no collision whatsoever. Ideally you even have a DNS alias pointing to the corresponding service: