Skip to content

Commit 01e972a

Browse files
committed
Merge branch 'release/v.2.7.5'
Add xml feature #31 enhance some feature add unit test for xml feature and add handler response base on media type
2 parents bee3ee2 + bc2f597 commit 01e972a

File tree

22 files changed

+2858
-387
lines changed

22 files changed

+2858
-387
lines changed

README.md

Lines changed: 118 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,143 @@
11
[![dekaulitz](https://circleci.com/gh/dekaulitz/MockyUp.svg?style=shield)](https://app.circleci.com/pipelines/github/dekaulitz/MockyUp)
22

3-
<h2>Simplify The Integration as Fast as You can</h2>
4-
<h2>MockyUp</h2>
3+
# Simplify The Integration as Fast as You can
4+
5+
## MockyUp
56
MockyUp is an Openapi mock server that allow You to centralize the Openapi collections that can consuming You're Openapi spec and generating the mock as You want by You're own definitions.
67
We are using `OpenApi Spesification version 3.x.x` and bundled with <a href="https://swagger.io/tools/swagger-ui/"> Swagger UI </a><br/>
7-
For now we only supporting json request and json response or string response.
8-
8+
For now we only supporting json request and xml request.
99

10-
<h2>Stacks</h2>
11-
MockyUp build from SpringBoot and Swagger library and backed with mongodb as database and UI with vue js. For UI referencing you can check <a href="https://github.com/dekaulitz/mockup-frontend">Mockup UI Repository</a>.
10+
## Stacks
11+
MockyUp build with SpringBoot and Swagger library and backed with mongodb as database and UI with vue js. For UI referencing you can check <a href="https://github.com/dekaulitz/mockup-frontend">Mockup UI Repository</a>.
1212
We are creating new extension parameter on OpenApi spec for generating the mock response in this case we adding `x-examples` properties for set the mock.
1313

14-
<h2>Requirements</h2>
15-
* MongoDb 4.x.x
16-
* Java at least 1.8.x
17-
* Docker (optional)
14+
## Requirements
15+
16+
* MongoDb 4.x.x.
17+
* Java at least 1.8.x.
18+
* Docker (optional).
1819

1920

20-
<h2>Features</h2>
21-
Yes You can of crouse You can :
21+
## Features
22+
Yes You can of course You can :
23+
2224
* You can mock the response base on Path parameter.
2325
* You can mock the response base on Body request parameter.
2426
* You can mock the response base on Header request parameter.
2527
* You can mock the response base on Query string parameter.
2628
* You can defining the HttpCode response.
27-
* You can defining the Header properites.
29+
* You can defining the Header properties.
2830

29-
In this case You has full control for the response as You want with You're own definition base on criterias that You want to mock, and You can create mock user story base on the user properties or request properties that You want to try.
31+
In this case You have full control for the response as You want with You're own definitions base on criterias that You want to mock, and You can create mock user story base on the user properties or request properties that You want to try.
3032
This will helping You to try perfect integration before the real integration before You're application ready.
3133

32-
<h2>How to use</h2>
33-
You can refer the example of OpenApi spec that already including the `x-examples` properties from <a href="https://raw.githubusercontent.com/dekaulitz/MockyUp/master/src/main/resources/public/example_mocking_books.json">here</a>.<br/>
34-
Change the application properties that matched with You're machine.
35-
For `x-examples` extension that has some attributes. They are :
34+
## How to use
35+
You can refer the example of OpenApi spec that already including the `x-examples` properties from <a href="https://raw.githubusercontent.com/dekaulitz/MockyUp/master/src/main/resources/public/example_mocking_books.json">here</a>
36+
or for more context you can check the documentation about OpenApi <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md">here</a>.<br/>
37+
38+
We adding new extension for set mock configuration. They are:
3639

3740
* x-query-including, it will matching the query string request.
3841
* x-header-including, it will matching the header request.
3942
* x-path-including, it will matching the path parameter request
4043
* x-default, if you defined the x-default if above criterias does'nt matched it will rendering the response by default response.
4144

42-
And then you run the Appilication like usuall or using `docker-compose`.
43-
For the first time Application will check the user root is exist or not, if the user was not exist Application will create the user root with password root by default.
44-
45-
Do login with the user that already created. And create new spec or just paste example spec from <a href="https://raw.githubusercontent.com/dekaulitz/MockyUp/master/src/main/resources/public/example_mocking_books.json">here</a>
46-
and open the spec and choose swagger ui and edit `testing_path` with id database and `host` to You're application host like `localhost:7070`.
47-
And start to request.
48-
49-
50-
51-
52-
45+
### x-query-including,x-header-including,x-body-including and x-path-including configurations
46+
```
47+
[{
48+
"property": {
49+
"name": "client-id",// this is the field property
50+
"value": "empty" // this is the field value
51+
},
52+
"response": {
53+
"httpCode": 200, //http code
54+
// you can add mock header response
55+
"headers": {
56+
"x-request-id": "this is from mock", //header response added by mock
57+
},
58+
// if you want to mock the response body base on media type
59+
"content": {
60+
"application/json": {
61+
"response":{
62+
// you can mock the response directly
63+
"value": "something"
64+
}
65+
},
66+
"application/xml": {
67+
// you can mock the response by the reference
68+
"$ref": "#/components/examples/LIST_OF_BOOKS_EMPTY_XML"
69+
}
70+
},
71+
// if you want add the response body direclty without media type
72+
"response":{
73+
"value": "something"
74+
}
75+
// if you want to add the response body by the reference without media type
76+
"$ref": "#/components/examples/LIST_OF_BOOKS_EMPTY"
77+
}
78+
}]
79+
```
80+
You should defined the configuration if you want to mocking the response base on path parameter,query parameter, header parameter and body request like above.
81+
if the property matched with request properties will rendering the response as the response request.
82+
83+
### x-default configuration
84+
```
85+
{
86+
"response": {
87+
"httpCode": 200,//http code
88+
// you can add mock header response
89+
"headers": {
90+
"x-request-id": "this is from mock",//header response added by mock
91+
},
92+
// if you want to mock the response body base on media type
93+
"content": {
94+
"application/json": {
95+
"$ref": "#/components/examples/LIST_OF_BOOKS_EMPTY"
96+
},
97+
"application/xml": {
98+
// you can mock the response by the reference
99+
"$ref": "#/components/examples/LIST_OF_BOOKS_EMPTY_XML"
100+
}
101+
},
102+
// if you want add the response body direclty without media type
103+
"response":"#/components/examples/LIST_OF_BOOKS_EMPTY"
104+
// if you want to add the response body by the reference without media type
105+
"$ref": "#/components/examples/LIST_OF_BOOKS_EMPTY"
106+
}
107+
}
108+
```
109+
This `x-default` configuration when the request is not matched with other configuration `x-default` will rendering the responsse.
110+
111+
### How to integrate
112+
MockyUp will running as mock server and mock collection server. You can directly hit the MockypUp mocking endpoint for test mocking the response.
113+
```
114+
http://[mockyup_hostname]/mocks/mocking/[mock_id]?path=[contract_endpoint]
115+
```
116+
Or do test via swagger
117+
```
118+
http://[mockyup_hostname]/swagger/[mock_id]
119+
```
120+
Before that you should add new server env on youre spec.
121+
```
122+
...
123+
"servers":[
124+
{
125+
"url": "http://{host}/mocks/mocking/{mock_id}?path=",
126+
"description": "Testing locally",
127+
"variables": {
128+
"host": {
129+
"default": "localhost:7070"
130+
},
131+
"mock_id": {
132+
"description": "mock id from database"
133+
}
134+
}
135+
}
136+
...
137+
]
138+
```
139+
You can check the example configuration spec from <a href="https://raw.githubusercontent.com/dekaulitz/MockyUp/master/src/main/resources/public/example_mocking_books.json">here</a>
140+
## Supported
141+
<a href="https://www.jetbrains.com/?from=MockyUp"><img src="https://github.com/dekaulitz/MockyUp/blob/feature/addXmlFeature/src/main/resources/public/jetbrains-variant-2.png" height="100"/></a>
53142

54143

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@
108108
<artifactId>junit</artifactId>
109109
<scope>test</scope>
110110
</dependency>
111+
<dependency>
112+
<groupId>com.fasterxml.jackson.dataformat</groupId>
113+
<artifactId>jackson-dataformat-xml</artifactId>
114+
</dependency>
115+
<!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
111116
</dependencies>
112117

113118
<build>

src/main/java/com/github/dekaulitz/mockyup/base/controller/BaseController.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
*/
2626
public class BaseController {
2727

28+
private static final String XML_MEDIA_TYPE = "application/xml";
29+
private static final String JSON_MEDIA_TYPE = "application/json";
2830
protected Logger LOGGER = LoggerFactory.getLogger(this.getClass());
2931

3032
/**
@@ -35,14 +37,15 @@ public class BaseController {
3537
*/
3638
protected ResponseEntity<Object> generateMockResponseEntity(MockHelper mock) {
3739
HttpHeaders httpHeaders = new HttpHeaders();
38-
if (mock.getResponse().getHeaders() != null) {
39-
for (Map.Entry headerMap : mock.getResponse().getHeaders().entrySet()) {
40+
if (mock.getResponseProperty().getHeaders() != null) {
41+
for (Map.Entry headerMap : mock.getResponseProperty().getHeaders().entrySet()) {
4042
httpHeaders.add(headerMap.getKey().toString(), headerMap.getValue().toString());
4143
}
4244
}
43-
return ResponseEntity.status(mock.getResponse().getHttpCode()).headers(httpHeaders).body(mock.getResponse().getResponse());
45+
return ResponseEntity.status(mock.getResponseProperty().getHttpCode()).headers(httpHeaders).body(mock.getResponseProperty().getResponse());
4446
}
4547

48+
4649
/**
4750
* handling error response with type of class exception
4851
*

src/main/java/com/github/dekaulitz/mockyup/controllers/MockControllers.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ public ResponseEntity<String> greeting() throws IOException {
8080
*/
8181
@RequestMapping(value = "/mocks/mocking/{id}", method = {RequestMethod.OPTIONS, RequestMethod.DELETE,
8282
RequestMethod.POST, RequestMethod.GET, RequestMethod.HEAD, RequestMethod.PATCH, RequestMethod.PUT,
83-
RequestMethod.TRACE},
84-
produces = MediaType.APPLICATION_JSON_VALUE
83+
RequestMethod.TRACE}
8584
)
8685
public ResponseEntity<Object> mockingPath(@NonNull @RequestParam(value = "path") String path,
8786
@PathVariable String id, @RequestBody(required = false) String body,

src/main/java/com/github/dekaulitz/mockyup/domain/mocks/base/BaseMockModel.java

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.slf4j.LoggerFactory;
2020

2121
import javax.servlet.http.HttpServletRequest;
22+
import java.io.IOException;
2223
import java.io.UnsupportedEncodingException;
2324
import java.util.ArrayList;
2425
import java.util.List;
@@ -90,8 +91,8 @@ public void setUpdateMockEntity(MockVmodel body, MockEntities mockEntities) thro
9091
* @throws UnsupportedEncodingException if encoding query string is fail
9192
*/
9293
public MockHelper renderingMockResponse(PathItem pathItem, HttpServletRequest request, String body, String[] openApiRoutePath, String[] paths, Components components)
93-
throws NotFoundException, JsonProcessingException, InvalidMockException, UnsupportedEncodingException {
94-
MockHelper mock = null;
94+
throws NotFoundException, IOException, InvalidMockException {
95+
MockHelper mock;
9596

9697
//parsing pathitem into JsonNode
9798
//its because from the pathItem you its more easier for geting type of method request that wanted
@@ -104,6 +105,7 @@ public MockHelper renderingMockResponse(PathItem pathItem, HttpServletRequest re
104105
if (ops.getExtensions() == null) throw new NotFoundException(ResponseCode.MOCKUP_NOT_FOUND);
105106

106107
//get custom extension for mock response from operation with extension [x-examples]
108+
@SuppressWarnings("unchecked")
107109
Map<String, Object> examples = (Map<String, Object>) ops.getExtensions().get(MockHelper.X_EXAMPLES);
108110
if (examples == null) throw new NotFoundException(ResponseCode.MOCKUP_NOT_FOUND);
109111

@@ -121,35 +123,45 @@ public MockHelper renderingMockResponse(PathItem pathItem, HttpServletRequest re
121123
*/
122124

123125
//get mock response from path
124-
if (extension.getKey() == MockHelper.X_PATH) {
125-
mock = MockHelper.generateResponsePath((List<Map<String, Object>>) extension.getValue(), openApiRoutePath, paths, components);
126+
if (extension.getKey().equals(MockHelper.X_PATH)) {
127+
@SuppressWarnings("unchecked")
128+
List<Map<String, Object>> extensionValues = (List<Map<String, Object>>) extension.getValue();
129+
mock = MockHelper.generateResponsePath(request,extensionValues, openApiRoutePath, paths, components);
126130
if (mock != null) return mock;
127131
}
128132

129133
//get mock from query string
130-
if (extension.getKey() == MockHelper.X_QUERY) {
131-
mock = MockHelper.generateResponseQuery(request, (List<Map<String, Object>>) extension.getValue(), components);
134+
if (extension.getKey().equals(MockHelper.X_QUERY)) {
135+
@SuppressWarnings("unchecked")
136+
List<Map<String, Object>> extensionValues = (List<Map<String, Object>>) extension.getValue();
137+
mock = MockHelper.generateResponseQuery(request, extensionValues, components);
132138
if (mock != null) return mock;
133139
}
134140

135141
//checking the mock from the headers
136-
if (extension.getKey() == MockHelper.X_HEADERS) {
137-
mock = MockHelper.generateResponseHeader(request, (List<Map<String, Object>>) extension.getValue(), components);
142+
if (extension.getKey().equals(MockHelper.X_HEADERS)) {
143+
@SuppressWarnings("unchecked")
144+
List<Map<String, Object>> extensionValues = (List<Map<String, Object>>) extension.getValue();
145+
mock = MockHelper.generateResponseHeader(request, extensionValues, components);
138146
if (mock != null) return mock;
139147
}
140148

141149
//checking the mock from the boyd
142-
if (extension.getKey() == MockHelper.X_BODY) {
143-
mock = MockHelper.generateResponseBody(request, (List<Map<String, Object>>) extension.getValue(), body, components);
150+
if (extension.getKey().equals(MockHelper.X_BODY)) {
151+
@SuppressWarnings("unchecked")
152+
List<Map<String, Object>> extensionValues = (List<Map<String, Object>>) extension.getValue();
153+
mock = MockHelper.generateResponseBody(request, extensionValues, body, components);
144154
if (mock != null) return mock;
145155
}
146156

147157
//if there is no mock defined on path,header,query and body but default was defined
148-
if (extension.getKey() == MockHelper.X_DEFAULT) {
149-
mock = MockHelper.generateResponseDefault((Map<String, Object>) extension.getValue(), components);
150-
if (mock != null) return mock;
158+
if (extension.getKey().equals(MockHelper.X_DEFAULT)) {
159+
@SuppressWarnings("unchecked")
160+
Map<String, Object> extensionValues = (Map<String, Object>) extension.getValue();
161+
mock = MockHelper.generateResponseDefault(request,extensionValues, components);
162+
return mock;
151163
}
152164
}
153-
return mock;
165+
return null;
154166
}
155167
}

src/main/java/com/github/dekaulitz/mockyup/domain/mocks/base/MockInterface.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.springframework.data.domain.Pageable;
1717

1818
import javax.servlet.http.HttpServletRequest;
19+
import java.io.IOException;
1920
import java.io.UnsupportedEncodingException;
2021
import java.util.List;
2122

@@ -99,7 +100,7 @@ public interface MockInterface {
99100
* @throws UnsupportedEncodingException when the contract is not valid structure
100101
* @throws InvalidMockException when the contract is not valid with the request
101102
*/
102-
MockHelper getMockMocking(HttpServletRequest request, String path, String id, String body) throws NotFoundException, JsonProcessingException, UnsupportedEncodingException, InvalidMockException;
103+
MockHelper getMockMocking(HttpServletRequest request, String path, String id, String body) throws NotFoundException, IOException, InvalidMockException;
103104

104105
/**
105106
* add user to mock

src/main/java/com/github/dekaulitz/mockyup/domain/mocks/models/MockModel.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.springframework.stereotype.Service;
3030

3131
import javax.servlet.http.HttpServletRequest;
32+
import java.io.IOException;
3233
import java.io.UnsupportedEncodingException;
3334
import java.util.Date;
3435
import java.util.List;
@@ -196,7 +197,7 @@ public List<DtoMockupDetailVmodel> getDetailMockUpIdByUserAccess(String id, Auth
196197
* @throws InvalidMockException when the contract is not valid with the request
197198
*/
198199
@Override
199-
public MockHelper getMockMocking(HttpServletRequest request, String path, String id, String body) throws NotFoundException, JsonProcessingException, UnsupportedEncodingException, InvalidMockException {
200+
public MockHelper getMockMocking(HttpServletRequest request, String path, String id, String body) throws NotFoundException, IOException, InvalidMockException {
200201
//find the collection base on mock id
201202
Optional<MockEntities> mockEntities = this.mockRepository.findById(id);
202203
if (!mockEntities.isPresent())
@@ -331,7 +332,7 @@ private void checkAccessModification(MockEntities mockEntities, AuthenticationPr
331332
* @throws JsonProcessingException
332333
*/
333334
private MockHelper validatePathWithOpenApiPaths(HttpServletRequest request, String body, OpenAPI openAPI, String[] extractPathRequest)
334-
throws UnsupportedEncodingException, InvalidMockException, NotFoundException, JsonProcessingException {
335+
throws IOException, InvalidMockException, NotFoundException {
335336
//iterate all pathitem from openApi
336337
for (Map.Entry<String, PathItem> entry : openAPI.getPaths().entrySet()) {
337338
//get path route from pathItem from openapi path

src/main/java/com/github/dekaulitz/mockyup/domain/mocks/vmodels/DtoMockResponseVmodel.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import lombok.Getter;
44
import lombok.NoArgsConstructor;
55
import lombok.Setter;
6+
import org.springframework.http.MediaType;
67

78
import java.util.Map;
89

@@ -13,6 +14,11 @@ public class DtoMockResponseVmodel {
1314
private int httpCode;
1415
private Object response;
1516
private Map<String, Object> headers;
17+
private Object $ref;
18+
private Map<String, Map<String, Object>> content;
19+
20+
21+
private String mediaType;
1622

1723
public Object get$ref() {
1824
return $ref;
@@ -22,6 +28,12 @@ public class DtoMockResponseVmodel {
2228
this.$ref = $ref;
2329
}
2430

25-
private Object $ref;
26-
31+
public void setMediaType(String mediaType) {
32+
if (mediaType != null) {
33+
String[] acceptHeader = mediaType.split(",");
34+
if (acceptHeader.length > 1)
35+
mediaType = MediaType.APPLICATION_JSON_VALUE;
36+
}
37+
this.mediaType = mediaType;
38+
}
2739
}

src/main/java/com/github/dekaulitz/mockyup/infrastructure/configuration/filters/RequestFilter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ protected void doFilterInternal(final HttpServletRequest request, final HttpServ
5151
req.put("responseStatus", response.getStatus());
5252
log.info("{}", this.logsMapper.logRequest(req));
5353
MDC.remove(ConstantsRepository.REQUEST_ID);
54-
MDC.remove(ConstantsRepository.REQUEST_TIME);
54+
MDC.remove(ConstantsRepository.PATH_ENDPOINT);
5555
}
5656

5757
private String getxRequestID(HttpServletRequest request) {

0 commit comments

Comments
 (0)