Skip to content

Commit 6211635

Browse files
committed
feat(http-provider): add new plugin http-provider
1 parent 3baccd5 commit 6211635

File tree

19 files changed

+2610
-0
lines changed

19 files changed

+2610
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: 'Check Pull Request for plugin: http provider'
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
paths:
7+
- 'http-provider/**'
8+
9+
jobs:
10+
tests:
11+
name: Unit tests
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v4
15+
- name: Set up JDK 21 for x64
16+
uses: actions/setup-java@v4
17+
with:
18+
java-version: '21'
19+
distribution: 'temurin'
20+
architecture: x64
21+
22+
- name: Set up Node.js 18
23+
uses: actions/setup-node@v4
24+
with:
25+
node-version: '18'
26+
27+
- name: Start fake HTTP server
28+
working-directory: src/test/fake-http-server
29+
run: |
30+
npm install
31+
npm run start &
32+
sleep 5
33+
34+
- name: Install Pandoc
35+
run: sudo apt-get update && sudo apt-get install -y pandoc
36+
37+
- name: Execute unit tests
38+
run: mvn -ntp -pl http-provider test
39+
40+
- name: Execute mutation tests
41+
run: mvn -ntp org.pitest:pitest-maven:mutationCoverage
42+
43+
- name: Extract summary from pitest
44+
run: echo "<html><head></head><body><h1>Pit Test Coverage Report</h1><h3>Project Summary</h3>" > pitest.html && perl -0777 -ne 'print "$1\n" if /(<table>.*?<\/table>)/s' target/pit-reports/index.html >> pitest.html && echo "</body></html>" >> pitest.html
45+
46+
- name: Convert pitest report to markdown
47+
run: pandoc --from html --to markdown_github --no-highlight pitest.html
48+
49+
- name: Post comment
50+
uses: luukkemp/pr-comment@2024.1
51+
env:
52+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53+
with:
54+
path: pitest.html
55+
56+
- name: Execute sonar scan
57+
env:
58+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
59+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
60+
run: mvn -ntp sonar:sonar -Dsonar.token=$SONAR_TOKEN -Dsonar.branch.name=${{ github.head_ref }}

http-provider/README.md

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# 🌐 HttpProviderPlugin
2+
3+
The `HttpProviderPlugin` is a provider plugin designed to interact with configurable HTTP REST APIs, supporting full CRUD operations and response mapping into dynamic entities.
4+
5+
## ✅ Use Case
6+
7+
Use this plugin when you need to:
8+
9+
* Integrate a data source accessible via HTTP REST API.
10+
* Dynamically configure endpoints, HTTP methods, and request bodies.
11+
* Transform HTTP responses into dynamic entities.
12+
* Insert pre- and post-response mapping phases for custom processing.
13+
14+
## 🔧 Configuration
15+
16+
### Minimal Example
17+
18+
```yaml
19+
providers:
20+
- type: http
21+
name: http
22+
baseUrl: https://myapi.com # mandatory
23+
24+
entities:
25+
- name: user
26+
provider: http
27+
route: users
28+
disabledRoutes: ['patch', 'findAll']
29+
tasks:
30+
- type: response-to-json
31+
phases: [
32+
"beforeResponseMappingCreate",
33+
"beforeResponseMappingUpdate",
34+
# "beforeResponseMappingPatch", -> this phase is unused
35+
"beforeResponseMappingDelete",
36+
"beforeResponseMappingFindById",
37+
# "beforeResponseMappingFindAll" -> this phase is unused
38+
]
39+
access:
40+
create:
41+
uri: /api/users
42+
method: POST
43+
body: >
44+
{
45+
"name": "{{ entity.name }}"
46+
}
47+
entityMapping:
48+
id: {{ response.id }}
49+
delete:
50+
uri: /api/users/{{ entity.id }}
51+
method: DELETE
52+
result: true
53+
findById:
54+
uri: /api/users/{{ entity.id }}
55+
method: GET
56+
entityMapping:
57+
id: {{ response.id }}
58+
update:
59+
uri: /api/users/{{ entity.id }}
60+
method: PUT
61+
body: >
62+
{
63+
"name": "{{ entity.name }}"
64+
}
65+
entityMapping:
66+
id: {{ response.id }}
67+
```
68+
69+
### Full Example with Pagination and Mapping
70+
71+
```yaml
72+
entities:
73+
- name: user
74+
provider: http
75+
route: users
76+
disabledRoutes: ['create', 'update', 'patch', 'delete', 'findById']
77+
tasks:
78+
- type: response-to-json
79+
phases: ["beforeResponseMappingFindAll"]
80+
access:
81+
findAll:
82+
uri: /api/users
83+
method: GET
84+
page: {{ response.page }}
85+
size: {{ response.size }}
86+
total: {{ response.totalElements }}
87+
itemsCount: {{ response.elements.size() }}
88+
entityMapping:
89+
id: {{ response.elements[index].id }}
90+
```
91+
92+
### Configuration Fields
93+
94+
| Key | Required | Description |
95+
| ------------------------------------- | -------- | -------------------------------------------------------------------------------------------- |
96+
| `baseUrl` | ✅ | Base URL of the HTTP API |
97+
| `headers` | ❌ | Optional HTTP headers (e.g., `Content-Type`, `Authorization`) |
98+
| `disabledRoutes` | ❌ | List of disabled actions for the entity (e.g., `patch`, `findAll`) |
99+
| `access` | ❌ | Specific configuration for each CRUD action (`create`, `update`, `delete`, `findById`, etc.) |
100+
| `uri` | ✅ | Endpoint URI (supports Jinja templating) |
101+
| `method` | ✅ | HTTP method (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`) |
102+
| `body` | ❌ | HTTP request body (supports Jinja templating) |
103+
| `entityMapping` | ❌ | Maps fields from the HTTP response to the dynamic entity |
104+
| `result` | ❌ | Expression evaluated to verify success (e.g., for `delete`) |
105+
| `page`, `size`, `total`, `itemsCount` | ❌ | Pagination info for `findAll`; mapping can use `index` for iterating items. |
106+
107+
## 🛠 Behavior
108+
109+
* For each CRUD action, the plugin executes two lifecycle phases **before** and **after** the response mapping:
110+
111+
* `beforeResponseMappingCreate` / `afterResponseMappingCreate`
112+
* `beforeResponseMappingUpdate` / `afterResponseMappingUpdate`
113+
* `beforeResponseMappingPatch` / `afterResponseMappingPatch`
114+
* `beforeResponseMappingDelete` / `afterResponseMappingDelete`
115+
* `beforeResponseMappingFindById` / `afterResponseMappingFindById`
116+
* `beforeResponseMappingFindAll` / `afterResponseMappingFindAll`
117+
118+
* These phases allow inserting custom logic at precise points during entity processing.
119+
120+
* The plugin consists of two types:
121+
122+
* **Provider plugin**: handles HTTP calls and entity mapping.
123+
* **Task plugin**: can run during lifecycle phases to perform operations like converting HTTP responses to JSON.
124+
125+
### Example of a Task plugin configuration
126+
127+
```yaml
128+
entities:
129+
- name: user
130+
provider: http
131+
route: users
132+
disabledRoutes: ['patch', 'findAll']
133+
tasks:
134+
- type: response-to-json
135+
phases: [
136+
"beforeResponseMappingCreate",
137+
"beforeResponseMappingUpdate",
138+
"beforeResponseMappingPatch",
139+
"beforeResponseMappingDelete",
140+
"beforeResponseMappingFindById",
141+
"beforeResponseMappingFindAll"
142+
]
143+
```
144+
145+
This `response-to-json` task plugin converts raw HTTP responses into JSON before entity mapping.
146+
147+
## 🧷 Important Notes
148+
149+
* Templating uses Jinja (via `JinjaService`) to dynamically inject entity and response values.
150+
* If a route is declared in `disabledRoutes`, the plugin ignores any corresponding `access` configuration.
151+
* The `findAll` entity mapping must always use an `index` parameter to iterate over the response items.
152+
* The plugin naturally integrates with the task engine to allow customized processing on responses.
153+
154+
---
155+
156+
## 🧪 How to Run Tests
157+
158+
To run the tests including the HTTP fake server:
159+
160+
1. Navigate to the fake HTTP server directory:
161+
162+
```bash
163+
cd src/test/fake-http-server
164+
```
165+
166+
2. Install the necessary Node.js dependencies:
167+
168+
```bash
169+
npm install
170+
```
171+
172+
3. Start the fake HTTP server in the background:
173+
174+
```bash
175+
npm run start &
176+
```
177+
178+
4. In another terminal (or after starting the server), run the Maven tests:
179+
180+
```bash
181+
mvn test
182+
```
183+
184+
This setup launches a local fake HTTP server that your tests use to simulate HTTP API calls. Running `mvn test` then executes the unit tests and integration tests relying on this server.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<module version="4">
3+
<component name="AdditionalModuleElements">
4+
<content url="file://$MODULE_DIR$" dumb="true">
5+
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
6+
<sourceFolder url="file://$MODULE_DIR$/src/test" isTestSource="true" />
7+
</content>
8+
</component>
9+
</module>

http-provider/pom.xml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>io.github.linagora.linid.im</groupId>
9+
<artifactId>linid-im-api-community-plugins</artifactId>
10+
<version>0.1.0</version>
11+
<relativePath>../pom.xml</relativePath>
12+
</parent>
13+
14+
<artifactId>http-provider-plugin</artifactId>
15+
<version>0.1.0</version>
16+
<name>http-provider-plugin</name>
17+
<description>Plugin to manage http provider</description>
18+
19+
<dependencies>
20+
<dependency>
21+
<groupId>org.springframework.boot</groupId>
22+
<artifactId>spring-boot-starter-webflux</artifactId>
23+
</dependency>
24+
<dependency>
25+
<groupId>com.hubspot.jinjava</groupId>
26+
<artifactId>jinjava</artifactId>
27+
<version>2.8.0</version>
28+
<scope>test</scope>
29+
</dependency>
30+
</dependencies>
31+
32+
</project>

0 commit comments

Comments
 (0)