Skip to content

Order service (and a shared tenant data helper)

Add the second business microservice, orders. It works exactly like products. To avoid copying the tenant plumbing, the sharding and scoped-credential code moves into the shared layer, so both services use it.

Method Path Body
GET /orders
POST /orders {"orderName": "...", "orderProducts": [{"productId": "...", "price": 10.5, "quantity": 2}]}
GET / PUT / DELETE /orders/{shardId:orderId} PUT takes the same body as POST

Table: partition key shardId (<tenantId>-<1..9>), sort key orderId. The line items are stored as a list of maps in orderProducts.

Step 05 put the “tenant data” logic inside the product service. Now that a second service needs it, it lives in server/src/layers/tenant_data.py:

Function Does
get_table(event, table_name) Pooled: boto3 table built from the authorizer’s scoped credentials. Silo: the function’s own role.
new_shard_id(tenant_id) tenant-a-<1..9>
split_key(event, key) Splits shardId:itemId and rejects shards of other tenants (PermissionError → 403)
query_all_shards(table, tenant_id) Queries the tenant’s 9 shards in parallel. Errors are re-raised instead of being lost in threads.

The service code now only knows its own entity. This is the “hide tenant details in a layer” pattern again: a developer adding a third service gets isolation for free by calling these helpers.

Also in this step:

  • utils.encode_to_json_object now uses json.dumps with a small default handler (Decimal → int/float, objects → __dict__, datetimes → ISO). The jsonpickle and simplejson dependencies are gone, along with their deprecation warnings.
  • Test setup (moto table + importing a service) moved into a load_service fixture in server/tests/conftest.py.
Terminal window
./scripts/deploy.sh you@example.com
Terminal window
A=$(./scripts/tenant-token.sh alice 'Passw0rd!Saas'); B=$(./scripts/tenant-token.sh bob 'Passw0rd!Saas')
curl -s -X POST -H "Authorization: Bearer $A" ${API}orders \
-d '{"orderName":"Alice order","orderProducts":[{"productId":"p1","price":10.5,"quantity":2}]}'
curl -s -H "Authorization: Bearer $A" ${API}orders

Results from the test deployment:

Call Result
alice creates an order {"key":"tenant-a-4:aec7...","orderName":"Alice order","orderProducts":[{"price":10.5,"productId":"p1","quantity":2}],...}
alice PUT her own order 200, quantity changed to 3
alice lists only Alice order v2
bob lists only Bob order
alice GET / DELETE bob’s order 403 each
alice’s scoped credentials GetItem on bob’s order AccessDeniedException
products after the refactor still ['Alice Gadget', 'Alice Widget v2']

Unit tests: 34 passed.

Step 07 adds tenant user management: tenant admins can create and manage users of their own tenant only.