# tapas-tasks Micro-service for Managing Tasks in a Task List implemented following Hexagonal Architecture. Based on examples from book "Get Your Hands Dirty on Clean Architecture" by Tom Hombergs Technologies: Java, Spring Boot, Maven **Note:** this repository contains an [EditorConfig](https://editorconfig.org/) file (`.editorconfig`) with default editor settings. EditorConfig is supported out-of-the-box by the IntelliJ IDE. To help maintain consistent code styles, we recommend to reuse this editor configuration file in all your services. ## HTTP API Overview The code we provide includes a minimalistic uniform HTTP API for (i) creating a new task, (ii) retrieving a representation of the current state of a task, and (iii) patching the representation of a task, which is mapped to a domain/integration event. The representations exchanged with the API use two media types: * a JSON-based format for task with the media type `application/task+json`; this media type is defined in the context of our project, but could be [registered with IANA](https://www.iana.org/assignments/media-types) to promote interoperability (see [TaskJsonRepresentation](src/main/java/ch/unisg/tapastasks/tasks/adapter/in/formats/TaskJsonRepresentation.java) for more details) * the [JSON Patch](http://jsonpatch.com/) format with the registered media type `application/json-patch+json`, which is also a JSON-based format (see sample HTTP requests below). For further developing and working with your HTTP API, we recommend to use [Postman](https://www.postman.com/). ### Creating a new task A new task is created via an `HTTP POST` request to the `/tasks/` endpoint. The body of the request must include a representation of the task to be created using the content type `application/task+json` defined in the context of this project. A valid representation must include at least two required fields (see [TaskJsonRepresentation](src/main/java/ch/unisg/tapastasks/tasks/adapter/in/formats/TaskJsonRepresentation.java) for more details): * `taskName`: a string that represents the name of the task to be created * `taskType`: a string that represents the type of the task to be created A sample HTTP request with `curl`: ```shell curl -i --location --request POST 'http://localhost:8081/tasks/' \ --header 'Content-Type: application/task+json' \ --data-raw '{ "taskName" : "task1", "taskType" : "computation", "originalTaskUri" : "http://example.org", "inputData" : "1+1" }' HTTP/1.1 201 Location: http://localhost:8081/tasks/cef2fa9d-367b-4e7f-bf06-3b1fea35f354 Content-Type: application/task+json Content-Length: 170 Date: Sun, 17 Oct 2021 21:03:34 GMT { "taskId":"cef2fa9d-367b-4e7f-bf06-3b1fea35f354", "taskName":"task1", "taskType":"computation", "taskStatus":"OPEN", "originalTaskUri":"http://example.org", "inputData":"1+1" } ``` If the task is created successfuly, a `201 Created` status code is returned together with a representation of the created task. The response also includes a `Location` header filed that points to the URI of the newly created task. ### Retrieving a task The representation of a task is retrieved via an `HTTP GET` request to the URI of task. A sample HTTP request with `curl`: ```shell curl -i --location --request GET 'http://localhost:8081/tasks/cef2fa9d-367b-4e7f-bf06-3b1fea35f354' HTTP/1.1 200 Content-Type: application/task+json Content-Length: 170 Date: Sun, 17 Oct 2021 21:07:04 GMT { "taskId":"cef2fa9d-367b-4e7f-bf06-3b1fea35f354", "taskName":"task1", "taskType":"computation", "taskStatus":"OPEN", "originalTaskUri":"http://example.org", "inputData":"1+1" } ``` ### Patching a task REST emphasizes the generality of interfaces to promote uniform interaction. For instance, we can use the `HTTP PATCH` method to implement fine-grained updates to the representational state of a task, which may translate to various domain/integration events. However, to conform to the uniform interface contraint in REST, any such updates have to rely on standard knowledge — and thus to hide away the implementation details of our service. In addition to the `application/task+json` media type we defined for our uniform HTTP API, a standard representation format we can use to specify fine-grained updates to the representation of tasks is [JSON Patch](http://jsonpatch.com/). In what follow, we provide a few examples of `HTTP PATCH` requests. For further details on the JSON Patch format, see also [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902)). #### Changing the status of a task from OPEN to ASSIGNED Sample HTTP request that assigns the previously created task to group `tapas-group1`: ```shell curl -i --location --request PATCH 'http://localhost:8081/tasks/cef2fa9d-367b-4e7f-bf06-3b1fea35f354' \ --header 'Content-Type: application/json-patch+json' \ --data-raw '[ {"op" : "replace", "path": "/taskStatus", "value" : "ASSIGNED" }, {"op" : "add", "path": "/serviceProvider", "value" : "tapas-group1" } ]' HTTP/1.1 200 Content-Type: application/task+json Content-Length: 207 Date: Sun, 17 Oct 2021 21:20:58 GMT { "taskId":"cef2fa9d-367b-4e7f-bf06-3b1fea35f354", "taskName":"task1", "taskType":"computation", "taskStatus":"ASSIGNED", "originalTaskUri":"http://example.org", "serviceProvider":"tapas-group1", "inputData":"1+1" } ``` In this example, the requested patch includes two JSON Patch operations: * an operation to `replace` the `taskStatus` already in the task's representation with the value `ASSIGNED` * an operation to `add` to the task's representation a `serviceProvider` with the value `tapas-group1` Internally, this request is mapped to a [TaskAssignedEvent](src/main/java/ch/unisg/tapastasks/tasks/application/port/in/TaskAssignedEvent.java). The HTTP response returns a `200 OK` status code together with the updated representation of the task. #### Changing the status of a task from to EXECUTED Sample HTTP request that changes the status of the task to `EXECUTED` and adds an output result: ```shell curl -i --location --request PATCH 'http://localhost:8081/tasks/cef2fa9d-367b-4e7f-bf06-3b1fea35f354' \ --header 'Content-Type: application/json-patch+json' \ --data-raw '[ {"op" : "replace", "path": "/taskStatus", "value" : "EXECUTED" }, {"op" : "add", "path": "/outputData", "value" : "2" } ]' HTTP/1.1 200 Content-Type: application/task+json Content-Length: 224 Date: Sun, 17 Oct 2021 21:32:25 GMT { "taskId":"cef2fa9d-367b-4e7f-bf06-3b1fea35f354", "taskName":"task1", "taskType":"computation", "taskStatus":"EXECUTED", "originalTaskUri":"http://example.org", "serviceProvider":"tapas-group1", "inputData":"1+1", "outputData":"2" } ``` Internally, this request is mapped to a [TaskExecutedEvent](src/main/java/ch/unisg/tapastasks/tasks/application/port/in/TaskExecutedEvent.java). The HTTP response returns a `200 OK` status code together with the updated representation of the task.