7.5 Ask it
dotnet run --urls http://localhost:5080The catalogue needs nobody signed in:
curl -s http://localhost:5080/trax/graphql -H 'Content-Type: application/json' \
-d '{"query":"{ discover { products(order: { sku: ASC }) { nodes { sku name price stock } } } }"}'{"data":{"discover":{"products":{"nodes":[{"sku":"CAP","name":"Cap","price":18.50,"stock":0},{"sku":"MUG","name":"Mug","price":12.00,"stock":10},{"sku":"TEE","name":"T-shirt","price":25.00,"stock":3}]}}}}Your stock is lower, after the orders of the earlier chapters. The row version is not a field: the
schema serves IProductListing, not Product.
Place an order as ada. The answer carries the run's externalId, which is how a run is named to
everything that can follow it:
ADA=$(curl -s http://localhost:5080/dev/token/ada)
curl -s http://localhost:5080/trax/graphql -H "Authorization: Bearer $ADA" \
-H 'Content-Type: application/json' -d '{
"query": "mutation Place($input: PlaceOrderInput!) { dispatch { placeOrder(input: $input) { externalId output { orderId total } } } }",
"variables": { "input": { "paymentToken": "tok_visa", "lines": [{ "sku": "MUG", "quantity": 1 }] } }
}'{"data":{"dispatch":{"placeOrder":{"externalId":"f3e0f595ed6a472b926c46dbaf671e8d","output":{"orderId":"c5625240-1274-4e08-b2ff-2115a19fc9aa","total":12.00}}}}}Read the run back, step by step:
curl -s http://localhost:5080/trax/graphql -H "Authorization: Bearer $ADA" \
-H 'Content-Type: application/json' -d '{
"query": "query Progress($runId: String!) { runProgress(runId: $runId) { state steps { position name state } problem { code } } }",
"variables": { "runId": "f3e0f595ed6a472b926c46dbaf671e8d" }
}'{"data":{"runProgress":{"state":"COMPLETED","steps":[{"position":0,"name":"IdentifyCustomerJunction","state":"COMPLETED"},{"position":1,"name":"PriceCartJunction","state":"COMPLETED"},{"position":2,"name":"AssessRiskJunction","state":"COMPLETED"},{"position":3,"name":"LooksFraudulent","state":"COMPLETED"},{"position":4,"name":"LooksFraudulent","state":"COMPLETED"},{"position":5,"name":"(withheld)","state":"COMPLETED"},{"position":6,"name":"(withheld)","state":"COMPLETED"},{"position":7,"name":"(withheld)","state":"COMPLETED"}],"problem":null}}}Use your own externalId. The first three steps are the junctions before the fraud check. Then
the question is asked and routed on, as two steps. After that the names are withheld, and that is
deliberate: which junctions ran after a decision says what was decided, and a customer is not told
how the fraud check judged them. [TraxRunProgress(Answers = true)] would show them, and the
answer with them, for a train whose decisions its caller may see.
A run is followed by the caller who started it and by nobody else. Ask the same as grace and the
answer is NOT_FOUND, the same answer as for a run that does not exist, so it tells her nothing
about ada's orders:
{"data":{"runProgress":{"state":null,"steps":[],"problem":{"code":"NOT_FOUND"}}}}A run started over a mutation returns once it has finished, so here the steps are all done. A
subscription to the same runProgress streams each step as it happens, which matters once runs
are queued and take longer than a request.
Errors come back as GraphQL errors. A plain TrainException keeps its message for the customer,
under the code TRAX_TRAIN_ERROR:
{"errors":[{"message":"The card was declined.","path":["dispatch","placeOrder"],"extensions":{"code":"TRAX_TRAIN_ERROR"}}],"data":{"dispatch":{"placeOrder":null}}}Anything else is masked, so the payment provider's timeout, with our provider's name in its message, reaches the customer as:
{"errors":[{"message":"Unexpected Execution Error","path":["dispatch","placeOrder"]}],"data":{"dispatch":{"placeOrder":null}}}This is why chapter 1 threw TrainException for every message meant for the customer and nothing
else.
SDK Reference
AddTraxGraphQL | TraxMutation | Query models | Run progress | AddJunctionEvents | dispatch mutations
Next: 7.6 Test it