HTTP REST API
An HTTP REST API as an input adapter in a hexagonal architecture serves as the interface for handling HTTP requests from clients. This adapter translates HTTP requests into calls to the core application's use cases and returns appropriate HTTP responses. Here's how it fits into the architecture:
Role of an HTTP REST API as an Input Adapter
-
Handling HTTP Requests:
- The adapter receives HTTP requests from clients (e.g., browsers, mobile apps).
-
Request Translation:
- It translates these HTTP requests into calls to the application's use cases (services). This involves parsing request parameters, headers, and bodies.
-
Interfacing with Use Cases:
- It interacts with the application's input ports, which represent the use cases. These ports expose the core application's functionality in a technology-agnostic manner.
-
Generating HTTP Responses:
- After processing the request, the adapter translates the results from the core application into HTTP responses, setting appropriate status codes and headers.
Benefits of HTTP REST API as Input Adapter
- Decoupling: Decouples the external HTTP interface from the core application logic.
- Separation of Concerns: Handles the specifics of HTTP request parsing and response formatting, allowing the core application to focus on business logic.
- Testability: Allows the core application logic to be tested independently of the HTTP interface.
- Flexibility: Supports different types of clients (e.g., web browsers, mobile apps) without changing the core application logic.
Using an HTTP REST API as an input adapter in hexagonal architecture ensures that the application remains adaptable and maintainable, supporting various external interfaces while keeping the core business logic isolated and testable.
How Torpedo implements HTTP adapter
Torpedo generates its code on top of Gin Gonic.
Controller
The created controller logic is split in two files once torpedo command is executed to generate the code. The outcome will be:
classDiagram
inputGinBase <|-- InputGin
inputGinBase : IService service
inputGinBase : log.ILogger logger
inputGinBase: +Create()
inputGinBase: +Read()
inputGinBase: +Update()
inputGinBase: +Delete()
inputGinBase: +TQL()
As developer
As a developer your input logic MUST BE written into the Controller (InputGin) class in order to avoid that Torpedo code generation tool overwrite your code!
Data Transfer Object
The DTO is generated by Torpedo, letting you add custom fields if it is required and cannot be handled from the entity schema definition.
Basically Torpedo DTOs are an aggregation of different DTOs with their own semantic. Here is a diagram that illustrates this:
classDiagram
class MetadataDTO
class ReadOnlyDTO
class WriteableDTO
class RelationshipsDTO
class CustomDTO
MetadataDTO --o FullDTO : Aggregation
ReadOnlyDTO --o FullDTO : Aggregation
WriteableDTO --o FullDTO : Aggregation
RelationshipsDTO --o FullDTO : Aggregation
CustomDTO --o FullDTO : Aggregation
- MetadataDTO: This DTO contains the Torpedo entity generated fields like
id
,created
andupdated
. - ReadOnlyDTO: When a field is set as readonly within the entity schema its input field will be mapped in this one.
- WriteableDTO: Basically all the (non-readonly) defined fields will be written as fields of this DTO.
- RelationshipsDTO: When a relationship is defined as
hasMany
, a linked list of linked entity will be placed here. - CustomDTO: Each time that you need to define a field that is usefull for some entity use case but is not defined on the schema, must be coded here.
- FullDTO: This one is the aggregation DTO that contains all the preious DTO. So, when you need the complete DTO to map to the entity model, this is the one.
CustomDTO
Important: This is the only one DTO that is not overwritten by the autogeneration tool.
API endpoints
The API endpoints for CRUD operations are generated automatically per entity following the next pattern:
Operation | Method | Endpoint | Description |
---|---|---|---|
Create | POST |
/api/v1/$.spec.plural | Create an entity object |
Read | GET |
/api/v1/$.spec.plural/:id | Read an entity object |
Update | PUT |
/api/v1/$.spec.plural/:id | Update an entity object |
Delete | DELETE |
/api/v1/$.spec.plural/:id | Delete an entity object |
Query | POST |
/api/v1/$.spec.plural/query | Query an entity object |
GET the entire collection
At this point maybe you should notice that there isn't a GET /api/v1/$.spec.plural
endpoint. This one is replaced by the Query endpoint
letting you fetch all collection entities with filters, pagination and more.
Additionally, as shown at the entity definition Input section, the resource name can be set only for the input:
Operation | Method | Endpoint | Description |
---|---|---|---|
Create | POST |
/api/v1/blog-post | Create an entity object |
Read | GET |
/api/v1/blog-post/:id | Read an entity object |
Update | PUT |
/api/v1/blog-post/:id | Update an entity object |
Delete | DELETE |
/api/v1/blog-post/:id | Delete an entity object |
Query | POST |
/api/v1/blog-post/query | Query an entity object |