Testing a service application locally
Overview
This guide provides two ways of testing a service Connect application on your local machine:
Example scenario
A user has added a product to their cart, and an automatic discount of 10% should be applied to the cart's total price.
Use sample data
Requirements
- Your application must expose an
http
server on port8080
.
Sample calls
Input
The service application will be called via POST
request and the input is provided as the body payload.
The two example payloads are for creating or updating a Cart.
{"action": "Create","resource": {"typeId": "cart","id": "bcaeb291-5151-434c-80a9-c1ce7c88e6e0","obj": {"type": "Cart","id": "bcaeb291-5151-434c-80a9-c1ce7c88e6e0","version": 1,"createdAt": "1970-01-01T00:00:00.000Z","lastModifiedAt": "1970-01-01T00:00:00.000Z","lastModifiedBy": {"clientId": "hG7GPF-DdGZPEiamZKpOfZPP","isPlatformClient": false},"createdBy": {"clientId": "hG7GPF-DdGZPEiamZKpOfZPP","isPlatformClient": false},"lineItems": [{"id": "aab03288-fd14-4bb1-9a23-e506774ac040","productId": "56fc033e-25de-484b-bf31-fc0b97143aa9","name": {"en": "Some Product"},"productType": {"typeId": "product-type","id": "e1861d9b-6666-4461-8bb5-e579128c9a65","version": 1},"productSlug": {"en": "product_slug_fake_connector"},"variant": {"id": 1,"sku": "SKU-fake","prices": [{"id": "a09471bc-d9d6-4147-a390-7ac558f93c3c","value": {"type": "centPrecision","currencyCode": "EUR","centAmount": 4000,"fractionDigits": 2}}],"images": [],"attributes": [],"assets": []},"price": {"id": "a09471bc-d9d6-4147-a390-7ac558f93c3c","value": {"type": "centPrecision","currencyCode": "EUR","centAmount": 4000,"fractionDigits": 2}},"quantity": 1,"discountedPricePerQuantity": [],"perMethodTaxRate": [],"addedAt": "2023-06-05T13:36:40.555Z","lastModifiedAt": "2023-06-05T13:36:40.555Z","state": [{"quantity": 1,"state": {"typeId": "state","id": "90506fd6-479c-4cdc-9302-aff56b4c67b1"}}],"priceMode": "Platform","lineItemMode": "Standard","totalPrice": {"type": "centPrecision","currencyCode": "EUR","centAmount": 4000,"fractionDigits": 2},"taxedPricePortions": []}],"cartState": "Active","totalPrice": {"type": "centPrecision","currencyCode": "EUR","centAmount": 4000,"fractionDigits": 2},"shippingMode": "Single","shipping": [],"customLineItems": [],"discountCodes": [],"directDiscounts": [],"inventoryMode": "None","taxMode": "Platform","taxRoundingMode": "HalfEven","taxCalculationMode": "LineItemLevel","deleteDaysAfterLastModification": 90,"refusedGifts": [],"origin": "Customer","itemShippingAddresses": [],"totalLineItemQuantity": 1}}}
{"action": "Update","resource": {"typeId": "cart","id": "0a1552e1-101e-4840-b401-744c67a331c1","obj": {"type": "Cart","id": "0a1552e1-101e-4840-b401-744c67a331c1","version": 7,"createdAt": "2023-06-05T13:41:22.428Z","lastModifiedAt": "2023-06-05T13:42:20.904Z","lastModifiedBy": {"clientId": "hG7GPF-DdGZPEiamZKpOfZPP","isPlatformClient": false},"createdBy": {"clientId": "hG7GPF-DdGZPEiamZKpOfZPP","isPlatformClient": false},"lineItems": [{"id": "1c27a1db-289d-4934-89c1-c67b04db0496","productId": "56fc033e-25de-484b-bf31-fc0b97143aa9","name": {"en": "Some Product"},"productType": {"typeId": "product-type","id": "e1861d9b-6666-4461-8bb5-e579128c9a65","version": 1},"productSlug": {"en": "product_slug_fake_connector"},"variant": {"id": 1,"sku": "SKU-fake","prices": [{"id": "00b0e361-7b8b-464a-b25f-2b78715a1418","value": {"type": "centPrecision","currencyCode": "USD","centAmount": 3100,"fractionDigits": 2}},{"id": "a09471bc-d9d6-4147-a390-7ac558f93c3c","value": {"type": "centPrecision","currencyCode": "EUR","centAmount": 4000,"fractionDigits": 2}}],"images": [],"attributes": [],"assets": []},"price": {"id": "a09471bc-d9d6-4147-a390-7ac558f93c3c","value": {"type": "centPrecision","currencyCode": "EUR","centAmount": 4000,"fractionDigits": 2}},"quantity": 3,"discountedPricePerQuantity": [],"perMethodTaxRate": [],"addedAt": "2023-06-05T13:41:22.421Z","lastModifiedAt": "2023-06-05T13:42:51.770Z","state": [{"quantity": 3,"state": {"typeId": "state","id": "90506fd6-479c-4cdc-9302-aff56b4c67b1"}}],"priceMode": "Platform","lineItemMode": "Standard","totalPrice": {"type": "centPrecision","currencyCode": "EUR","centAmount": 12000,"fractionDigits": 2},"taxedPricePortions": []}],"cartState": "Active","totalPrice": {"type": "centPrecision","currencyCode": "EUR","centAmount": 12000,"fractionDigits": 2},"shippingMode": "Single","shipping": [],"customLineItems": [],"discountCodes": [],"directDiscounts": [],"inventoryMode": "None","taxMode": "Platform","taxRoundingMode": "HalfEven","taxCalculationMode": "LineItemLevel","deleteDaysAfterLastModification": 90,"refusedGifts": [],"origin": "Customer","itemShippingAddresses": [],"totalLineItemQuantity": 3}}}
Call your application
Call your application endpoint including the Create Cart or Update Cart in the payload:
curl -X POST http://localhost:8080/{endpoint} \-H 'Content-Type: application/json' \-d '{Create/Update Cart payload}'
Response
Service applications are expected to use the API Extension response and return a list of actions (mutations) on the triggered resource. You should check if the list of returned update actions follows your application's logic. In this example, it should return an update action for applying a 10% discount to the Cart as follows:
{"actions": [{"action": "setDirectDiscounts","discounts": [{"value": {"type": "relative","permyriad": 1000},"target": {"type": "lineItems","predicate": "1=1"}}]}]}
Use an API Extension
Requirements
- Your application must expose an
http
server on port8080
. - Have a local install of ngrok or similar software.
Objectives of this guide
By the end of this guide you will have:
- Created an API Extension that is triggered when a Cart is created or updated.
- Created a service Connect application that is called when the API Extension is triggered.
Expose your application
To set up an API Extension our service must be accessible from the Composable Commerce API. The following example uses ngrok to expose your machine with a public Domain Name System (DNS), but you can use similar applications/tools to do so.
# examplengrok http 8080# response: https://public-sample.ngrok-free.app
Set up the API Extension extension
With a public DNS, we can now create an API Extension on Composable Commerce. As mentioned in our use case, this example will trigger the API Extension every time a Cart is created or updated.
curl --location 'https://api.{region}.commercetools.com/{projectKey}/extensions' \--header 'Content-Type: application/json' \--header 'Authorization: Bearer <token>' \--data '{"destination" : {"type" : "HTTP","url" : "https://public-sample.ngrok-free.app"},"triggers" : [ {"resourceTypeId" : "cart","actions" : [ "Create", "Update" ]} ],"key" : "my-extension"}'
Trigger the API Extension
Send an API call to Composable Commerce to create or update an existing Cart:
curl --location 'https://api.{region}.commercetools.com/{projectKey}/carts' \--header 'Content-Type: application/json' \--header 'Authorization: Bearer <token>' \--data '{"currency": "EUR","shipping": [],"customShipping": [],"lineItems": [{"productId": {productId},"variantId": 1}]}'
Review the results
You should now review your application's logs and the resource to confirm if the application was successful.