Skip to content

Instantly share code, notes, and snippets.

@danhawkins
Last active February 16, 2025 15:52
Show Gist options
  • Save danhawkins/ed48e251677e6cfa6cb2e5afe2d20908 to your computer and use it in GitHub Desktop.
Save danhawkins/ed48e251677e6cfa6cb2e5afe2d20908 to your computer and use it in GitHub Desktop.
Data Flow Example

Data flow Example

POST /api/fulfilment/orders

Request is received using a dedicated request struct CreateOrderRequest this request struct has all the relevant annotations and validations for that request ONLY, it can use shared records, something like types.AddressRequest but shared types MUST be setup for request validation also.

IMPORTANT do not use data from order service or API here as it will make it easy to break API contracts

the CreateOrderRequest will be validated using go validator and there is example code on how to use that. It will automatically run any nested validations, for available validations check go validator docs

There should also be an appropriate CreateOrderResponse

CreateOrder(ctx context.Context, req CreateOrderRequest) (CreateOrderResponse, error)

Call a domain service with the relevant data that the domain expected, as domain services cannot have awareness of api structs, you need to convert into something the internal domain expected, this is one idea behind a unified standard internal data schema, so you always know what you want to convert into

Now I know in the case of fulfilment was want to call ex api to create the order, but as thats part of the domain responsibility, I think it make sense to first convert into a domain struct, then back out to the ex api data, that will also give is better ownershiup and clarity on the data we care about, and easier migration away from ex-core api.

So typically here if you have convertors, they can live in the api layber, but their job is to convert to internal data

CreateOrderRequest -> data.PickingOrder for example

Then something like domainService.CreateOrder(ctx, convertedOrder)

Fulfiment Public Domain

As fulfilment public api is meant to just be a convenient public facing wrapper around our fulfilment domain, I don't think any data structs should exist here, like data.PickingOrder, that should live in fulfilment/domain/data (or similar) if you already have data.PickingOrder, then this should be called something else.

You can have the service to receive the CreateOrder request in the fulfilment_public/domain or fulfilment/domain so long as the data structs are not in the public one

CreateOrder(ctx, data.Order) (data.Order, error)

Typically in this layer we would persist the order, but in the case of fulfilment right now this would convert from unified data and make a request to ex_core_api

Summary

Essentially we are saying that both sides of the interation, the public API and ExCoreAPI should be able to convert to the common data struct, the conversion into the common data should ideally not be in the domain but between the domain and the external call, this we we can ensure we don't get any circular dependencies, and data is flowing the right with, and we don't inadvertantly break API contracts by changing underlying data types

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment