Question

I am making a REST API in Go using PostgreSQL.

Quick introduction:

I suddenly have a case where I have different variations of the same basic entity, one of the variations have maybe 12 extra fields than the base, and two other variants have a few more fields. I have mapped this using the Inherits syntax in Postgres which saves me a lot of time, it is not as feature rich though, it gives you some benefits if you want to select from all of the child tables at the same time e.g. a union fetching only the base fields. But poses problems when you wan't to figure out in which child table a specific ID is.

My actual problem:

Implementing a GetOne taking in just a ID without polluting my public API contract with unnecessary complexity. The ID could belong to any of the children and need all of the fields from that child table. I have used embedded structs in Go to map the inheritance in the structs and used inheritance in the database so I would really like a pretty solution to tie this thing together. I was thinking about a few solutions to this very classical problem, as follows:

  • Polute my restful API by saying 'okay these entities are different' and make a entity/<type>/<id> kind of endpoint, I would then do some normal switch logic in my store which would have a model for each of these entities.

  • Create a stored procedure handling all of this in the database, and when the result comes back I do some kind of check that sees what fields I got back and from that identify the type, I could e.g. introduce a type field in the base of the entities to make this easy to validate. I would then just return a interface{} from the model which is a kind of generic variable that can contain anything and just return that directly to the client code. This would definitely hide the complexity, but it doesn't feel like a very idiomatic Go way of doing it.

  • I could completely separate these and create controllers, models and stores for each of these variations of types which is a lot of typing, and hard to extend, so I think I would like to avoid this.

I don't think PostgreSQL has anything else to offer me functionality wise which would just fix this problem, I have been a long way away from design patterns though - it wouldn't surprise me if it could be solved with a strategy pattern or similar structural patterns.

Was it helpful?

Solution

I see three possibilities you might want to investigate further:

  1. Use PostgreSQLs JSON features to directly produce JSON payload you just pass through (row_to_json).
  2. Use PostgreSQLs JSON features to store the data in a document fashion way (jsonb column) instead of using inheritance. Then you can encode the documents in whatever way you want and can solve it with the best possible structure on the Go side.
  3. Use code generation to handle the many different structs, their mapping and encoding. Maybe use the Content-Type to help the API consumer differentiate what you just produced. (Or if you need it the other way around: look at the Accept header to find out what the client actually wants. Something like application/json+myAwesomeType is totally fine.)
Licensed under: CC-BY-SA with attribution
scroll top