Skip to content

Commit b8d9291

Browse files
authored
Merge pull request #848 from marle3003/develop
Develop
2 parents cf0e5a3 + 44acd0c commit b8d9291

21 files changed

Lines changed: 632 additions & 262 deletions

.github/actions/build-release-notes/action.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,3 @@ runs:
1313
echo
1414
echo "$BODY"
1515
} > docs/release.md
16-
- name: Upload UI artifact
17-
uses: actions/upload-artifact@v4
18-
with:
19-
name: release-notes
20-
path: docs/release.md

api/handler_mail.go

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package api
22

33
import (
44
"fmt"
5-
"mime"
65
"mokapi/media"
76
"mokapi/providers/mail"
87
"mokapi/runtime"
@@ -413,6 +412,11 @@ func getRejectResponse(r *mail.Rule) *rejectResponse {
413412
}
414413

415414
func toMessage(m *smtp.Message) *messageData {
415+
subject, err := smtp.DecodeHeaderValue(m.Subject)
416+
if err != nil {
417+
log.Printf("failed to decode subject '%s': %v", m.Subject, err)
418+
subject = m.Subject
419+
}
416420
r := &messageData{
417421
Server: m.Server,
418422
From: toAddress(m.From),
@@ -423,7 +427,7 @@ func toMessage(m *smtp.Message) *messageData {
423427
MessageId: m.MessageId,
424428
InReplyTo: m.InReplyTo,
425429
Date: m.Date,
426-
Subject: decodeSmtpValue(m.Subject),
430+
Subject: subject,
427431
ContentType: m.ContentType,
428432
ContentTransferEncoding: m.ContentTransferEncoding,
429433
Body: m.Body,
@@ -455,20 +459,15 @@ func toMessage(m *smtp.Message) *messageData {
455459
func toAddress(list []smtp.Address) []address {
456460
var r []address
457461
for _, a := range list {
462+
name, err := smtp.DecodeHeaderValue(a.Name)
463+
if err != nil {
464+
log.Printf("failed to decode address '%v': %v", a.Name, err)
465+
name = a.Name
466+
}
458467
r = append(r, address{
459-
Name: decodeSmtpValue(a.Name),
468+
Name: name,
460469
Address: a.Address,
461470
})
462471
}
463472
return r
464473
}
465-
466-
func decodeSmtpValue(s string) string {
467-
dec := new(mime.WordDecoder)
468-
r, err := dec.DecodeHeader(s)
469-
if err != nil {
470-
log.Errorf("failed to decode SMTP header: %v", err)
471-
return s
472-
}
473-
return r
474-
}

docs/config.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@
564564
{
565565
"label": "Mokapi behind Reverse Proxy",
566566
"source": "resources/examples/mokapi-behind-proxy.md",
567-
"path": "/resources/examples/mokapi-behind-proxy",
567+
"path": "/resources/examples/mokapi-behind-reverse-proxy",
568568
"hideNavigation": true
569569
},
570570
{
@@ -620,7 +620,7 @@
620620
{
621621
"label": "Bring Your Mock APIs to Life with Mokapi and JavaScript",
622622
"source": "resources/blogs/dynamic-mocks-with-javascript.md",
623-
"path": "/resources/blogs/dynamic-mocks-with-javascript",
623+
"path": "/resources/blogs/bring-your-mock-apis-to-life-with-javascript",
624624
"hideNavigation": true
625625
},
626626
{

docs/resources/blogs/dynamic-mocks-with-javascript.md

Lines changed: 92 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,155 +1,130 @@
11
---
2-
title: Create Smart API Mocks with Mokapi Scripts
3-
description: Tired of static mocks? Learn how Mokapi Scripts let you create dynamic mock APIs using JavaScript — perfect for development, testing, and rapid prototyping.
2+
title: Bring Your Mock APIs to Life with JavaScript
3+
description: Tired of static mocks? Mokapi Scripts let you create dynamic, intelligent mock APIs that react to real request data, powered by plain JavaScript.
4+
subtitle: Tired of static mocks? Mokapi Scripts let you create dynamic, intelligent mock APIs that react to real request data, powered by plain JavaScript.
45
---
56

6-
# Bring Your Mock APIs to Life with Mokapi and JavaScript
7+
# Bring Your Mock APIs to Life with JavaScript
78

8-
<img src="/mokapi-scripts.png" alt="Example JavaScript code for Mokapi Scripts with annotated benefits of using dynamic API mocks">
9+
Mocking APIs is essential for fast development, but static mocks can quickly become a bottleneck. What if your mock
10+
could think? Reacting to query parameters, headers, or body content. Simulating auth, errors, and pagination.
11+
Reflecting state changes across requests.
912

10-
Mocking APIs is essential for fast development — but static mocks can quickly
11-
become a bottleneck. Wouldn’t it be better if your mocks could think —
12-
reacting to queries, headers, or even generating data on the fly?
13+
That's exactly what Mokapi Scripts are designed for. With just a few lines of JavaScript, you can turn a flat
14+
JSON file into a dynamic, intelligent mock API.
1315

14-
That's exactly what [Mokapi Scripts](/docs/javascript-api/overview.md) are designed for.
15-
16-
With just a few lines of JavaScript, you can control how your mocks behave —
17-
making them dynamic, intelligent, and realistic.
16+
> No backend? No problem. With Mokapi Scripts, your mocks behave exactly the way you need them to, all in
17+
> familiar JavaScript or TypeScript, with no new DSL to learn.
1818
1919
## What Are Mokapi Scripts?
2020

21-
Mokapi Scripts are lightweight JavaScript modules that give you full control
22-
over how your mock APIs respond. Instead of static JSON, you define behavior
23-
based on request data — query strings, headers, body content, and more.
24-
25-
## Why Dynamic Mocks Matter
21+
Mokapi Scripts are lightweight JavaScript modules that sit alongside your OpenAPI or AsyncAPI specification.
22+
Instead of returning a fixed response, they let you define behavior, inspecting the incoming request and
23+
deciding what to send back.
2624

27-
Static mock responses are fine for simple cases, but they quickly fall short when:
25+
They're the difference between a mock that says *"here's a user"* and one that says *"here's the right user,
26+
given who's asking what role they have, and what they just posted."*
2827

29-
- Your frontend depends on different user roles (e.g., admin vs. regular user)
30-
- You need to simulate errors, timeouts, or permission checks
31-
- Backend state changes over time and should affect future responses (e.g., after a POST, the next GET reflects the update)
32-
- You need data that changes depending on query parameters or request bodies
33-
- You want to test workflows or sequences of API calls that depend on each other
34-
- You're working on features like pagination, filtering, or sorting
35-
- You need to simulate authentication and session-specific behavior
36-
- You want to create more realistic test scenarios for CI pipelines or manual testing
37-
- Your team needs fast feedback loops without relying on a fully working backend
28+
## Why Static Mocks Fall Short
3829

39-
Dynamic mocks make your development process more reliable, realistic, and efficient.
40-
41-
## What You Can Do with Mokapi Scripts
30+
Static responses are fine for trivial cases. But real development quickly surfaces their limits:
4231

43-
- ✅ Return different responses based on query parameters, headers, or body content
44-
- ✅ Simulate authentication, authorization, and role-based access
45-
- ✅ Generate random, structured, or context-aware dynamic data
46-
- ✅ Mock complex workflows with conditional logic and stateful behavior
47-
- ✅ Chain requests together to simulate real-world usage patterns
48-
- ✅ Customize error responses, delays, and status codes
32+
- **Role-based responses**
33+
Admin and regular users see different data. A static mock can only show one.
34+
- **Simulating errors & timeouts**
35+
You need your frontend to handle 403s, 429s, and network failures, but your mock always returns 200.
36+
- **Stateful workflows**
37+
After a POST, the next GET should reflect the change. Static mocks have no memory.
38+
- **Dynamic filtering & pagination**
39+
Query parameters like `?page=2` or `?name=laptop` should produce meaningful results.
40+
- **Sequential request chains**
41+
Login → fetch profile → update settings: static mocks can't model these flows.
42+
- **Auth & session behavior**
43+
Missing or invalid tokens should behave differently from valid ones in your test environment.
4944

50-
All using familiar JavaScript or TypeScript — no need to learn a new DSL.
45+
Dynamic mocks solve all of these. They make your development process more reliable, your test suites more
46+
realistic, and your feedback loops faster.
5147

52-
## Example: Conditional Response Based on a Query Parameter
48+
## What You Can Do with Mokapi Scripts
5349

54-
Let’s say your API returns a list of products. You want to simulate:
50+
- Return different responses based on query parameters, headers, or body content
51+
- Simulate authentication, authorization, and role-based access control
52+
- Generate random, structured, or context-aware dynamic data on the fly
53+
- Mock complex workflows with conditional logic and stateful behavior
54+
- Chain requests together to simulate real-world usage patterns
55+
- Customize error responses, status codes, and artificial delays
56+
- Mock an HTML login form to simulate an external identity provider
5557

56-
- A search operation when a query parameter (name) is provided
57-
- An error response when the query parameter is exactly "error"
58+
## Example: Dynamic Product Search
5859

59-
Here’s how easy it is with Mokapi Scripts:
60+
Let's build a realistic product list endpoint. It should:
61+
- Return the full product catalog when no filter is applied
62+
- Filter products by name when a ?name= query parameter is provided
63+
- Return a `400` error with a custom message when `?name=error` is passed
6064

61-
```typescript
62-
import { on } from 'mokapi';
65+
```javascript title=products.js
66+
import { on } from 'mokapi'
6367

6468
const products = [
65-
{ name: 'Laptop Pro 15' },
66-
{ name: 'Wireless Mouse' },
67-
{ name: 'Mechanical Keyboard' },
68-
{ name: 'Noise Cancelling Headphones' },
69-
{ name: '4K Monitor' },
70-
{ name: 'USB-C Hub' }
71-
];
69+
{ name: 'Laptop Pro 15' },
70+
{ name: 'Wireless Mouse' },
71+
{ name: 'Mechanical Keyboard' },
72+
{ name: 'Noise Cancelling Headphones' },
73+
{ name: '4K Monitor' },
74+
{ name: 'USB-C Hub' }
75+
]
7276

7377
export default () => {
74-
on('http', (request, response): boolean => {
75-
if (request.query.name) {
76-
if (request.query.name === 'error') {
77-
response.body = 'A custom error message';
78-
response.statusCode = 400;
79-
} else {
80-
const matchingProducts = products.filter(p =>
81-
p.name.toLowerCase().includes(request.query.name.toLowerCase())
82-
);
83-
response.data = {products: matchingProducts};
84-
return true;
85-
}
86-
}
87-
return false;
88-
});
89-
}
90-
```
91-
92-
### response.data vs. response.body
93-
In Mokapi, you control the response with either `response.data` or `response.body`:
94-
95-
#### `response.data`
78+
on('http', (request, response) => {
79+
const nameFilter = request.query.name
9680

97-
- Any JavaScript value (object, array, number, etc.)
98-
- Mokapi:
99-
- ✅ Validates it against your OpenAPI specification.
100-
- ✅ Converts it to the correct format (JSON, XML, etc.)
101-
102-
Use this when you want automatic validation and formatting.
81+
if (!nameFilter) {
82+
// No filter — return everything
83+
response.data = { products: products }
84+
return
85+
}
10386

104-
#### `response.body`
105-
- Must be a string.
106-
- Mokapi:
107-
- ❌ Skips validation
108-
- ✅ Gives you full control (e.g., raw HTML, plain text)
87+
if (nameFilter === 'error') {
88+
// Simulate a validation error
89+
response.rebuild(400)
90+
response.data.message = 'A custom error message'
91+
return
92+
}
10993

110-
Use this when you want to simulate freeform or invalid content.
94+
// Filter products by name (case-insensitive)
95+
const matched = products.filter(p =>
96+
p.name.toLowerCase().includes(nameFilter.toLowerCase())
97+
)
98+
99+
response.data = { products: matched }
100+
})
101+
}
102+
```
111103

112104
## Use Cases
113105

114-
### 1. Frontend Development
115-
116-
Test UI flows with realistic behavior — pagination, filtering, auth, and more —
117-
without waiting for backend implementation.
118-
119-
### 2. Testing and QA
120-
121-
Simulate edge cases, failures, and timeouts directly in your mock server —
122-
ideal for automated or manual testing.
123-
124-
### 3. Rapid Prototyping
125-
126-
Show real-world behavior in your prototypes using dynamic data. Build better
127-
demos and get faster feedback.
106+
- **Frontend Development**
107+
Test UI flows with realistic behavior—pagination, filtering, auth, and error states—without waiting for a working backend.
108+
- **Testing & QA**
109+
Simulate edge cases, failures, and timeouts directly in your mock server. Ideal for automated CI pipelines and manual exploratory testing.
110+
- **Rapid Prototyping**
111+
Show real-world behavior in demos and prototypes using dynamic data. Build faster, get feedback sooner.
128112

129113
## Getting Started
130114

131-
1. Write your OpenAPI or AsyncAPI spec (or generate it)
132-
2. Add a Script where you control the response with JavaScript
133-
3. Run Mokapi — that’s it!
134-
135-
👉 Try the [OpenAPI Mocking Tutorial](/resources/tutorials/get-started-with-rest-api) for a guided walkthrough.
136-
137-
👉 Check out the [Mokapi Installation Guide](/docs/get-started/installation.md) to get set up in minutes.
138-
139-
## Conclusion
140-
141-
Static mocks are yesterday’s solution. \
142-
Mokapi Scripts bring a new level of control, flexibility, and realism to your API development process — all powered by JavaScript.
143-
144-
No backend? No problem. \
145-
With Mokapi, your mocks behave exactly the way you need them to.
115+
1. **Write your specification**
116+
Start with an OpenAPI spec, or generate one from an existing service. This defines the shape of your API.
117+
2. **Add a Mokapi Script**
118+
Drop a JavaScript file next to your spec. Register event handlers that inspect the request and set the response however you need.
119+
3. **Run Mokapi**
120+
That's it. Your dynamic mock is live, validated against your spec, and visible in the Mokapi dashboard.
146121

147122
## Further Reading
148123

149-
- [Debugging Mokapi JavaScript](/resources/blogs/debugging-mokapi-scripts)\
150-
Learn how to debug your JavaScript code inside Mokapi
151-
- [End-to-End Testing with Mock APIs Using Mokapi](/resources/blogs/end-to-end-testing-with-mocked-apis)\
152-
Improve your end-to-end tests by mocking APIs with Mokapi.
124+
- [Debugging Mokapi JavaScript](/resources/blogs/debugging-mokapi-scripts)
125+
Learn how to use `console.log`, `console.error`, and event handler tracing to see exactly what your scripts are doing.
126+
- [End-to-End Testing with Mock APIs Using Mokapi](/resources/blogs/end-to-end-testing-with-mocked-apis)
127+
Improve your end-to-end test suites by replacing live backend dependencies with Mokapi.
153128

154129
---
155130

0 commit comments

Comments
 (0)