1Hepi is a command-line tool for testing REST APIs using YAML-based configurations. It supports environment management, dynamic data generation, and response chaining, allowing you to build complex test scenarios where results/state from one request is used in subsequent ones.
  2
  3## Installation
  4
  5```bash
  6go install github.com/mitjafelicijan/hepi@latest
  7```
  8
  9## Basic example
 10
 11```yaml
 12environments:
 13  local:
 14    host: http://localhost:8080
 15
 16requests:
 17  login:
 18    method: POST
 19    url: "{{host}}/v1/auth/login"
 20    description: "Authenticate and get a token"
 21    headers:
 22      Content-Type: "application/json"
 23    json:
 24      username: "admin"
 25      password: "secret-password"
 26
 27  get_profile:
 28    method: GET
 29    url: "{{host}}/v1/profile"
 30    description: "Fetch user profile using the token from login"
 31    headers:
 32      Authorization: "Bearer {{login.token}}"
 33      Accept: "application/json"
 34
 35groups:
 36  auth_flow:
 37    - login
 38    - get_profile
 39```
 40
 41## CLI Usage
 42
 43### Basic Usage
 44
 45```bash
 46# Execute a single request
 47hepi -env staging -file test.yaml -req create_user
 48
 49# Execute multiple requests
 50hepi -env staging -file test.yaml -req login,get_profile
 51
 52# Use a specific environment
 53hepi -env staging -file test.yaml -req get_status
 54```
 55
 56### Executing Groups
 57
 58```bash
 59# Execute a group of requests defined in the YAML
 60hepi -env staging -file test.yaml -group auth_flow
 61```
 62
 63### Overriding Variables
 64
 65You can override variables defined in the `environments` section by passing them as system environment variables. This is useful for CI/CD or quick testing.
 66
 67```bash
 68# Override the 'host' variable from the command line
 69host=https://httpbin.org go run main.go generators.go -env test -file test.yaml -group all
 70```
 71
 72### Variable Precedence
 73
 74When resolving `{{variable}}` placeholders, Hepi follows a strict lookup sequence. The first source to return a value wins.
 75
 761.  **System Environment**: Variables set in your shell or passed as command-line prefixes (e.g., `HOST=... go run ...`).
 772.  **Local `.env` File**: Variables loaded from a `.env` file in the current directory. These provide defaults that can be overridden by the system environment.
 783.  **YAML Environment**: Variables defined within the specific `environments` block selected via the `-env` flag.
 794.  **Persistent State**: Key-value pairs stored in `.hepi.json` from previous request executions (accessed via `{{request_name.path.to.key}}`).
 80
 81#### Rationale
 82
 83This hierarchy (System > .env > YAML > State) is designed for **dynamic runtime overrides**:
 84*   **Non-destructive testing**: Override values from the CLI without modifying the static YAML configuration.
 85*   **Secret Management**: Keep sensitive credentials in the environment or `.env` files to avoid committing them to version control.
 86*   **CI/CD Integration**: Automated pipelines can inject configuration via environment variables which seamlessly take precedence.
 87
 88
 89### Options
 90
 91*   `-env`: The environment to use.
 92*   `-file`: Path to the YAML configuration file.
 93*   `-req`: Comma-separated list of request names to execute.
 94*   `-group`: The name of a request group to execute.
 95*   `-headers`: Show response headers in the output.
 96*   `-timeout`: Request timeout duration (default: 10s).
 97*   `-state`: Path to state file (default: .hepi.json).
 98
 99## Core Concepts
100
101### Environments
102
103Environments allow you to define variables that change based on the target (e.g., local development vs. production). Each environment is a map of key-value pairs.
104
105### Requests
106
107Requests are the individual API calls you want to perform. Each request specifies its method, URL, headers, and body (`json`, `form`, or `files`).
108
109### Groups
110
111Groups are ordered lists of requests. Executing a group runs the requests in the specified sequence.
112
113## Configuration Syntax
114
115The configuration is defined in a YAML file (e.g., `test.yaml`).
116
117### Substitution Syntax
118
119Hepi uses two types of placeholders:
120
1211.  **`{{variable}}`**: Used for substituting values from:
122    *   **Environment Variables**: Values from a `.env` file (loaded automatically if present) or system environment variables.
123    *   **Config Variables**: Variables defined in the `environments` section of the YAML.
124    *   **Request State**: Values captured from previous request responses (e.g., `{{login_req.token}}`). For arrays, use index notation (e.g., `{{setup_project.members.0.name}}`).
1252.  **`[[generator]]`**: Used for generating dynamic data (e.g., `[[email]]`, `[[name]]`).
1263.  **`[[oneof: a, b, c]]`**: Randomly selects one of the provided values.
127
128### State Chaining (Persistence)
129
130When a request is executed, its response (if it's JSON) is stored in a local `.hepi.json` file. This allows subsequent requests to reference any field from the response using the `{{request_name.path.to.field}}` syntax.
131
132## Data Generators (Fakers)
133
134Hepi includes a wide range of generators for dynamic data. You can use these by wrapping the tag in double brackets, e.g., `[[email]]`.
135
136| Tag | Description |
137| :--- | :--- |
138| `name` | Random full name |
139| `first_name` | Random first name |
140| `last_name` | Random last name |
141| `email` | Random email address |
142| `username` | Random username |
143| `password` | Random password |
144| `url` | Random URL |
145| `phone` | Random phone number |
146| `int` | Random integer (0 - 1,000,000) |
147| `datetime` | Random time string |
148| `date` | Random date string |
149| `timestamp` | Random timestamp |
150| `uuid_hyphenated`| Random hyphenated UUID |
151| `jwt` | Random JWT token |
152| `ipv4` | Random IPv4 address |
153| `amount` | Random currency amount |
154| `word` | Random word |
155| `sentence` | Random sentence |
156| `real_address` | Random real-world address |
157| `cc_number` | Random credit card number |
158| `cc_type` | Random credit card type |
159| `domain_name` | Random domain name |
160| `ipv6` | Random IPv6 address |
161| `mac_address` | Random MAC address |
162| `unix_time` | Random Unix timestamp |
163| `currency` | Random currency code |
164
165*Refer to `generators.go` for the latest implementation of these functions.*
166
167## State File
168
169Hepi stores response data in `.hepi.json` in the current directory. This file is updated after every successful request that returns a JSON response. You can inspect this file or delete it to clear the "memory" of previous requests.
170
171## Examples
172
173### 1. Basic Request with Environments
174
175This example shows how to define multiple environments and a simple GET request that uses the `host` variable.
176
177```yaml
178environments:
179  local:
180    host: http://localhost:8080
181    api_key: "dev-key-123"
182  staging:
183    host: https://api.staging.example.com
184    api_key: "staging-key-456"
185
186requests:
187  get_status:
188    method: GET
189    url: "{{host}}/v1/status"
190    description: "Check API health status"
191    headers:
192      X-API-Key: "{{api_key}}"
193      Accept: "application/json"
194```
195
196To execute this request:
197```bash
198hepi -env local -file test.yaml -req get_status
199```
200
201### 2. Request with Dynamic Data
202
203Demonstrating the use of various generators to create a new resource with randomized data.
204
205```yaml
206environments:
207  local:
208    host: http://localhost:8080
209
210requests:
211  create_user:
212    method: POST
213    url: "{{host}}/v1/users"
214    description: "Create a new user with random profile data"
215    headers:
216      Content-Type: "application/json"
217    json:
218      name: "[[name]]"
219      email: "[[email]]"
220      username: "[[username]]"
221      password: "[[password]]"
222      profile:
223        bio: "[[sentence]]"
224        age: "[[int]]"
225        website: "[[url]]"
226        phone: "[[phone]]"
227```
228
229To execute this request:
230```bash
231hepi -env local -file test.yaml -req create_user
232```
233
234### 3. State Chaining (Persistence)
235
236This scenario shows a full authentication flow where the token from the login response is reused in a subsequent request.
237
238```yaml
239environments:
240  local:
241    host: http://localhost:8080
242
243requests:
244  login:
245    method: POST
246    url: "{{host}}/v1/auth/login"
247    description: "Authenticate and get a token"
248    headers:
249      Content-Type: "application/json"
250    json:
251      username: "admin"
252      password: "secret-password"
253
254  get_profile:
255    method: GET
256    url: "{{host}}/v1/profile"
257    description: "Fetch user profile using the token from login"
258    headers:
259      Authorization: "Bearer {{login.token}}"
260      Accept: "application/json"
261
262groups:
263  auth_flow:
264    - login
265    - get_profile
266```
267
268To execute this group:
269```bash
270hepi -env local -file test.yaml -group auth_flow
271```
272
273### 4. Form Data and Query Parameters
274
275Example of a complex search request using both query parameters and URL-encoded form data.
276
277```yaml
278environments:
279  local:
280    host: http://localhost:8080
281
282requests:
283  search_items:
284    method: POST
285    url: "{{host}}/v1/search"
286    description: "Search items with filters and pagination"
287    params:
288      q: "[[word]]"
289      page: "1"
290      limit: "20"
291      sort: "[[oneof: asc, desc]]"
292    form:
293      category: "[[oneof: electronics, books, clothing]]"
294      include_out_of_stock: "true"
295      min_price: "[[int]]"
296```
297
298To execute this request:
299```bash
300hepi -env local -file test.yaml -req search_items
301```
302
303### 5. Nested JSON, Arrays, and Header Subscriptions
304
305Showing how to handle complex data structures and reuse specific nested fields from previous state.
306
307```yaml
308environments:
309  local:
310    host: http://localhost:8080
311
312requests:
313  setup_project:
314    method: POST
315    url: "{{host}}/v1/projects"
316    description: "Create a complex project structure"
317    headers:
318      Content-Type: "application/json"
319    json:
320      title: "Project [[word]]"
321      settings:
322        visibility: "[[oneof: public, private]]"
323        notifications:
324          email: true
325          push: false
326      tags: ["active", "[[word]]", "[[word]]"]
327      members:
328        - name: "[[name]]"
329          role: "owner"
330        - name: "[[name]]"
331          role: "editor"
332
333  verify_project:
334    method: GET
335    url: "{{host}}/v1/projects/{{setup_project.id}}"
336    description: "Verify the project creation using the ID from the previous request"
337    headers:
338      X-Project-Owner: "{{setup_project.members.0.name}}"
339      Accept: "application/json"
340```
341
342To execute these requests:
343```bash
344hepi -env local -file test.yaml -req setup_project,verify_project
345```
346
347### 6. File Uploads (Multipart)
348
349Hepi supports uploading files using `multipart/form-data`. You can combine `form` fields and `files` in the same request.
350
351```yaml
352environments:
353  local:
354    host: http://localhost:8080
355
356requests:
357  upload_document:
358    method: POST
359    url: "{{host}}/v1/upload"
360    description: "Upload a document with metadata"
361    form:
362      category: "financial"
363      priority: "high"
364    files:
365      document: "path/to/report.pdf"
366      thumbnail: "path/to/image.png"
367```
368
369To execute this request:
370```bash
371hepi -env local -file test.yaml -req upload_document
372```
373
374### 7. CRUD Operations (PUT, PATCH, DELETE)
375
376Hepi supports all standard HTTP methods. This example shows how to update and delete resources.
377
378```yaml
379requests:
380  update_user:
381    method: PUT
382    url: "{{host}}/v1/users/{{create_user.id}}"
383    json:
384      name: "[[name]]"
385      active: true
386
387  patch_settings:
388    method: PATCH
389    url: "{{host}}/v1/users/{{create_user.id}}/settings"
390    form:
391      theme: "dark"
392      notifications: "enabled"
393
394  delete_user:
395    method: DELETE
396    url: "{{host}}/v1/users/{{create_user.id}}"
397    params:
398      force: "true"
399```
400
401To execute these requests:
402```bash
403hepi -env local -file test.yaml -req update_user,patch_settings,delete_user
404```