8

Given I have two microservices: Service A and Service B.

Service A owns full customer data and Service B requires a small subset of this data (which it gets from Service A through some bulk load say).

Both services store customers in their own database.

If service B then needs to interact with service A say to get additional data (e.g. GET /customers/{id}) it clearly needs a unique identifier that is shared between the two services.

Because the ids are GUIDs I could simply use the PK from Service A when creating the record in Service B. So both PKs match.

However this sounds extremely fragile. One option is to store the 'external Id' (or 'source id') as a separate field in Service B, and use that to interact with Service A. And probably this is a string as one day it may not be a GUID.

Is there a 'best practice' around this?

update

So I've done some more research and found a few related discussions:

Should you expose a primary key in REST API URLs?

Is it a bad practice to expose the database ID to the client in your REST API?

Slugs as Primary Keys

conclusion

I think my idea of trying to keep both Primary Keys for Customer the same across Service A and B was just wrong. This is because:

  1. Clearly PKs are service implementation specific, so they may be totally incompatible e.g. UUID vs auto-incremented INT.
  2. Even if you can guarantee compatibility, although the two entities both happen to be called 'Customer' they are effectively two (potentially very different) concepts and both Service A and Service B both 'own' their own 'Customer' record. What you may want to do though is synchronise some Customer data across those services.

So I now think that either service can expose customer data via its own unique id (in my case the PK GUID) and if one service needs to obtain additional customer data from another service it must store the other service identifier/key and uses that. So essentially back to my 'external id' or 'source id' idea but perhaps more specific as 'service B id'.

Mark Chidlow
  • 1,432
  • 2
  • 24
  • 43
  • It is not fragile but needed. Even if you use an external id, wouldn't that value still be stored in Service A as well to match the request from Service B? – Seth Dec 12 '20 at 06:04
  • 1
    Yes I need the external Id of course, but my question was whether to use these as database Primary Keys in both services. My suggestion is no, because this is a dependency on a) the PK on either Service not changing (which may not always be guaranteed) and b) the unique identifier for a customer may be say an email address and therefore cannot be used as a database PK. So I have really answered my own question here. I was really just hoping for a blog or article somewhere that would just validate this. – Mark Chidlow Dec 12 '20 at 09:01
  • 1
    Well, I guess this is the cool approach only that we can follow – Tushar Mahajan Dec 12 '20 at 10:04
  • 1
    Why would you need it in the first place? If its a customer, it likely has a customer ID the company uses internally (i.e. to put on the invoice or refer to the customer internally). This is your unique value, which you use to call the other service too. An GUID, autoincreement etc. "primary" key is just an RDBM tool for modeling relationships, which may be non-existent in an document based DB. Imagine an order and order position entity, for RDBMS you need an autoincrement column to model the relationships (i.e. assign the position to an order). – Tseng Dec 14 '20 at 08:34
  • 1
    The position also may have an position number, which is usually counting up and starts at 1 for every new order, but this is not suitable for a FK relation. Now, when you have a document database, the FK isn't necessary at all as the relationship is determined by the document structure, i.e. `{ "orderNumber": "O12345", "address": ..., "positions": [{ "positionNumber":1, "description": "Some Product", "priceNet": 10.00, ...]`. – Tseng Dec 14 '20 at 08:38
  • Via rest api you usually refer to the order as `/orders/{orderNum}` and the positions as `/orders/{orderNum}/positions` and a specific position: `/orders/{orderNum}/positions/({positionNum}`, hence not necessary to expose a primary key. P.S. its better to solve your issues with message bus though, every time the entity in Service A changes, it fires an change event to the message bus, Service B (and other services) pick their copy of the event and update the entity, so your services are not dependant. – Tseng Dec 14 '20 at 08:39
  • Having multiple services calling each other synchronously, isn't microservice. Its still a monolithic application split into multiple applications. One service becomes unavailable and the whole application stops working. That's the opposite of the microservice spirit – Tseng Dec 14 '20 at 08:41

3 Answers3

4

I think it depends a bit on the data source and your design. But, one thing I would avoid sharing is a Primary key which is a GUID or auto-increment integer to an external service. Those are internal details of your service and not what other services should take a dependency on.

I would rather have an external id which is more understood by other services and perhaps business as a whole. It could be a unique customer number, order number or a policy number as opposed to an id. You can also consider them as a "business id". One thing to also keep in mind is that an external id can also be exposed to an end-user. Hence, it is a ubiquitous way of identifying that "entity" across the entire organization and services irrespective of whether you have an Event-Driven-Design or if your services talk through APIs. I would only expose the DB ids to the infrastructure or repository. Beyond that, it is only a business/ external id.

Ankit Vijay
  • 3,752
  • 4
  • 30
  • 53
1

Well, if you have an idea on Value Object, a business ID will much better for designing.

DDD focus on business, an pure UUID/Auto increment ID can't present it.

Use a business meaning ID(UL ID), like a Customer ID, instead of a simple ID.

0

Suggestion: One can have auto-increment PK int ID which can be used for inter-service mapping/lookup. Advantage of having an autoincrement PK int ID is that it will be easier for database to index it as compared to a uuid/guid.

For exposing an entity identifier, one can have an additional universally unique ID in the table that will be exposed to the client app, hence only exposing what's necessary.

I hope that makes sense.