diff --git a/.gitignore b/.gitignore
old mode 100644
new mode 100755
index 6143e53..432f3a0
--- a/.gitignore
+++ b/.gitignore
@@ -1,22 +1,36 @@
-# Compiled class file
-*.class
+target/
+.mvn/
-# Log file
-*.log
+application-*.yml
-# BlueJ files
-*.ctxt
+### STS ###
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+*.DS_Store
-# Package Files #
-*.jar
-*.war
-*.ear
-*.zip
-*.tar.gz
-*.rar
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
+.gradle/
+
+### Application ###
+backup-temp/
+mocks-prod
+fake-api-data
+out
+bin
+.vscode
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..a0d3488
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,18 @@
+language: java
+jdk:
+- oraclejdk8
+before_cache:
+- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
+- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
+cache:
+ directories:
+ - "$HOME/.gradle/caches/"
+ - "$HOME/.gradle/wrapper/"
+script:
+- gradle check
+- gradle codeCoverageReport
+after_success:
+- bash <(curl -s https://codecov.io/bash) -t
+
+notifications:
+ email: false
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..e3cc9db
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,38 @@
+# Contributing
+:clap::tada: Thank you for taking the time to contribute! :tada::clap:
+
+We really value your willingness to contribute to this project. In order to higher the chances of your contribution being accepted, please refer to the following guidelines!
+
+## Steps
+
+1. Fork it!
+2. Create your feature branch: `git checkout -b feature/xyz develop`
+3. Commit your changes according to our commit message standards: `git commit -am 'feat(xyz) Added new functionality'`
+4. Push to your repo: `git push origin feature/xyz`
+5. Submit a pull request to `develop`
+
+## Workflow
+This repo uses Gitflow as its branch management system. You can learn more about Gitflow [here](https://www.atlassian.com/git/tutorials/comparing-workflows#gitflow-workflow).
+A few quick tips:
+* All feature branches should be based on `develop` and have the format `feature/branch_name`.
+* Minor bug fixes should be based on `master` and have the format `hotfix/branch_name`.
+
+### Commit Conventions
+In order to make the changelog generation easier we recommend the use of messages based on [Conventional Commits](https://conventionalcommits.org/).
+
+Examples:
+```
+feat(orders): added `XYZ` helper function
+
+commit description
+
+footer notes
+```
+
+```
+refactor(orders): refactored `ABC` helper function
+
+The behaviour of `ABC` was inconsistent and (...)
+
+BREAKING CHANGE: return type of `ABC` is now `String`
+```
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5760883
--- /dev/null
+++ b/README.md
@@ -0,0 +1,125 @@
+[](https://travis-ci.org/elemental-source/mock-api)
+[](https://codecov.io/github/elemental-source/mock-api?branch=master)
+[](https://www.codacy.com/app/elemental-source/mock-api?utm_source=github.com&utm_medium=referral&utm_content=elemental-source/mock-api&utm_campaign=Badge_Grade)
+
+## Coverage History
+
+
+# Mock API
+
+Allows for reusable http request/response cycles in your tests, similar to WireMock.
+
+## Features
+
+* Capture live responses from external hosts and save the stubs locally
+* Define your mocked responses using JSON
+* Folder-based data files
+* Per-request conditional proxying
+* Simple YAML configuration
+
+## Rules
+
+All your requests should be directed to the application. When an HTTP request is made, the following matching rules are applied:
+
+1. Is there a valid mock data file (i.e. request/response pattern) existing in `api.fileBase` folder that matches the request pattern? If so, the mocked response is returned.
+2. If not, does the request uri match any pattern described by the `api.uriConfigurations[].pattern` list? If so, the request will be dispatched to the matching `api.uriConfigurations[].host`.
+3. If none of above is true, the request is dispatched to the default host `api.host`.
+
+Should (2) or (3) occur, the response from an external host will be cached according to the `captureState` and `api.file.backup.path` properties. Next time the same request is made, it will be returned directly from the saved data file.
+
+## Example of a matched request
+
+Let's say you want to return the following mocked response for the following request:
+
+```
+GET http://www.example.com/payments/111/description?code=ABCD
+```
+
+Expected response:
+
+```
+HTTP 200 (OK)
+{
+ "payment": {
+ "from": "John",
+ "to": "Fred",
+ "value": 33
+ }
+}
+```
+
+You should create the following mock data file (its name has no meaning, it can be anything you like):
+
+```
+{
+ // Request field describes what the request should look like in order to return the matched response.
+ // In this case, query parameter "code" should be equal to "ABCD".
+ // The request pattern is described by its method, headers, query parameters and body.
+ request": {
+ "query": {
+ "code": "ABCD"
+ }
+ },
+ // Response field describes the mocked response in case the request matches.
+ // You can define the response body and status code.
+ "response": {
+ "body": {
+ "payment": {
+ "from": "John",
+ "to": "Fred",
+ "value": 33
+ }
+ },
+ "httpStatus": 200
+ }
+}
+```
+
+Now, in order to properly use the data file, we should consider where it should be located. `mock-api` will parse the request and use the uri to search for the data file in the `api.fileBase` folder. In our example the request uri is `/payments/111/description?code=ABCD`, this means that the data file should be located in `${api.fileBase}/payments/111/description` folder (i.e. file location is based in uri parts and path parameters, other request fields are described in the data file itself).
+
+## Requirements
+
+* Java JDK 8
+* Gradle 4
+
+## Run
+
+### Using Your Property File
+Create a valid property file in `src/main/resources/application-custom.yml` then run with `-Dspring.profiles.active=custom` argument. Example:
+
+```
+gradle bootRun -Dspring.profiles.active=custom
+```
+
+### Using Docker Image
+To generate the Docker image, run:
+
+```
+gradle buildDocker
+```
+
+By default, the image name will be `elemental-source/mock-api:VERSION`.
+
+In order to run the application, create two folders: one containing the `application-custom.yml` configuration file and the other containing the mock data files. Then run:
+
+```
+docker run -d --name mock-api \
+ -p 9090:9090 \
+ -p 5000:5000 \
+ -v /path/to/application-custom.yml:/config/application.yml \
+ -v /path/to/mock/data/files:/data \
+ elemental-source/mock-api:VERSION
+```
+
+Port `9090` exposes the service while port `5000` can be used to debug the application.
+
+You can check application logs from the container: `docker logs -f mock-api`
+
+## TODO
+
+- [X] Fix code Style
+- [ ] Create an example of a property file
+- [ ] Split unit from integrated tests
+- [ ] Fix skipping tests
+- [ ] Review dependencies (check, for instance, if it's even necessary to have both GSON and modelmapper dependencies)
+- [ ] Use objectmapper as component: `compile ('com.fasterxml.jackson.datatype: jackson-datatype-jdk8')``
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..04adf14
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,88 @@
+buildscript {
+ ext {
+ springBootVersion = '1.5.4.RELEASE'
+ }
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
+ classpath('se.transmode.gradle:gradle-docker:1.2')
+ }
+}
+
+apply plugin: 'java'
+apply plugin: 'eclipse'
+apply plugin: 'org.springframework.boot'
+apply plugin: 'jacoco'
+apply plugin: 'docker'
+apply plugin: 'findbugs'
+apply plugin: 'checkstyle'
+
+findbugs {
+ sourceSets = [sourceSets.main]
+ ignoreFailures = true
+ effort = "default"
+ reportLevel = "high"
+}
+
+checkstyle {
+ toolVersion = '8.3'
+ sourceSets= [sourceSets.main]
+ ignoreFailures = true
+}
+
+version = '4.0.0-SNAPSHOT'
+sourceCompatibility = 1.8
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compile('org.springframework.boot:spring-boot-starter')
+ compile 'org.springframework.boot:spring-boot-starter-undertow'
+ compile 'org.springframework.boot:spring-boot-starter-web'
+ compile 'org.springframework.boot:spring-boot-starter-hateoas'
+ compile 'com.google.code.gson:gson'
+ compile 'javax.ws.rs:javax.ws.rs-api:2.0'
+ compile 'net.minidev:json-smart:1.0.8'
+ compile 'com.google.guava:guava:22.0'
+ compile 'org.modelmapper:modelmapper:0.7.5'
+ compile 'commons-io:commons-io:2.5'
+ compile 'org.apache.httpcomponents:httpclient:4.4.1'
+ compile 'com.squareup.okhttp3:okhttp:3.8.1'
+ testCompile 'org.springframework.boot:spring-boot-starter-test'
+ testCompile 'br.com.six2six:fixture-factory:3.1.0'
+}
+
+bootRun {
+ String activeProfile = System.properties['spring.profiles.active']
+ systemProperty "spring.profiles.active", activeProfile
+}
+
+task codeCoverageReport(type: JacocoReport) {
+ executionData fileTree(project.rootDir.absolutePath).include("**/build/jacoco/*.exec")
+
+ sourceSets sourceSets.main
+ reports {
+ xml.enabled true
+ xml.destination "${buildDir}/reports/jacoco/report.xml"
+ html.enabled false
+ csv.enabled false
+ }
+}
+
+
+task buildDocker(type: Docker, dependsOn: build) {
+ push = false
+ applicationName = 'elemental-source/' + jar.baseName
+ dockerfile = file('src/main/docker/Dockerfile')
+ doFirst {
+ copy {
+ from jar
+ into stageDir
+ }
+ }
+}
+
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
new file mode 100644
index 0000000..2ea3261
--- /dev/null
+++ b/config/checkstyle/checkstyle.xml
@@ -0,0 +1,322 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..1a958be
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..681fe21
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Jul 10 15:07:48 BRT 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..4453cce
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save ( ) {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..e95643d
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/mocks-test/get/guests/132/1.json b/mocks-test/get/guests/132/1.json
new file mode 100755
index 0000000..dddbac5
--- /dev/null
+++ b/mocks-test/get/guests/132/1.json
@@ -0,0 +1,18 @@
+{
+ "response": {
+ "body": [
+ {
+ "cc": "11",
+ "ca": "12"
+ },
+ {
+ "cc": "21",
+ "ca": "22"
+ },
+ {
+ "cc": "31",
+ "ca": "32"
+ }
+ ]
+ }
+}
diff --git a/mocks-test/get/guests/132/users/1.json b/mocks-test/get/guests/132/users/1.json
new file mode 100755
index 0000000..614b8ce
--- /dev/null
+++ b/mocks-test/get/guests/132/users/1.json
@@ -0,0 +1,9 @@
+{
+ "response": {
+ "body": [
+ {
+ "move": "3"
+ }
+ ]
+ }
+}
diff --git a/mocks-test/get/guests/132/users/21/cc/1.json b/mocks-test/get/guests/132/users/21/cc/1.json
new file mode 100755
index 0000000..3f8c597
--- /dev/null
+++ b/mocks-test/get/guests/132/users/21/cc/1.json
@@ -0,0 +1,7 @@
+{
+ "response": {
+ "body": {
+ "tt": "789"
+ }
+ }
+}
diff --git a/mocks-test/get/guests/132/users/22/cc/1.json b/mocks-test/get/guests/132/users/22/cc/1.json
new file mode 100755
index 0000000..462294e
--- /dev/null
+++ b/mocks-test/get/guests/132/users/22/cc/1.json
@@ -0,0 +1,7 @@
+{
+ "response": {
+ "body": {
+ "tt": "456"
+ }
+ }
+}
diff --git a/mocks-test/get/payments/user/detail/1.json b/mocks-test/get/payments/user/detail/1.json
new file mode 100755
index 0000000..e5240de
--- /dev/null
+++ b/mocks-test/get/payments/user/detail/1.json
@@ -0,0 +1,18 @@
+{
+ "request": {
+ "query": {
+ "payment": "1",
+ "value": "10"
+ }
+ },
+ "response": {
+ "body": [
+ {
+ "total": "1700"
+ },
+ {
+ "total": "1800"
+ }
+ ]
+ }
+}
diff --git a/mocks-test/get/payments/user/detail/2.json b/mocks-test/get/payments/user/detail/2.json
new file mode 100755
index 0000000..3690a07
--- /dev/null
+++ b/mocks-test/get/payments/user/detail/2.json
@@ -0,0 +1,18 @@
+{
+ "request": {
+ "query": {
+ "payment": "2",
+ "value": "20"
+ }
+ },
+ "response": {
+ "body": [
+ {
+ "total": "1702"
+ },
+ {
+ "total": "1802"
+ }
+ ]
+ }
+}
diff --git a/mocks-test/get/person/11/1.json b/mocks-test/get/person/11/1.json
new file mode 100755
index 0000000..a24e97f
--- /dev/null
+++ b/mocks-test/get/person/11/1.json
@@ -0,0 +1,7 @@
+{
+ "response": {
+ "body": {
+ "name": "Paul"
+ }
+ }
+}
diff --git a/mocks-test/get/users/123/1.json b/mocks-test/get/users/123/1.json
new file mode 100755
index 0000000..a24e97f
--- /dev/null
+++ b/mocks-test/get/users/123/1.json
@@ -0,0 +1,7 @@
+{
+ "response": {
+ "body": {
+ "name": "Paul"
+ }
+ }
+}
diff --git a/mocks-test/get/users/123/2.json b/mocks-test/get/users/123/2.json
new file mode 100755
index 0000000..08e23df
--- /dev/null
+++ b/mocks-test/get/users/123/2.json
@@ -0,0 +1,13 @@
+{
+ "request": {
+ "query": {
+ "payment": "22"
+ }
+ },
+ "response": {
+ "body": {
+ "name": "John"
+ },
+ "httpStatus": 202
+ }
+}
diff --git a/mocks-test/patch/users/1456/1.json b/mocks-test/patch/users/1456/1.json
new file mode 100755
index 0000000..75b53ec
--- /dev/null
+++ b/mocks-test/patch/users/1456/1.json
@@ -0,0 +1,12 @@
+{
+ "request": {
+ "body": {
+ "result": "done"
+ }
+ },
+ "response": {
+ "body": {
+ "sync": "success"
+ }
+ }
+}
diff --git a/mocks-test/post/move/to/country/13/1.json b/mocks-test/post/move/to/country/13/1.json
new file mode 100755
index 0000000..b480e59
--- /dev/null
+++ b/mocks-test/post/move/to/country/13/1.json
@@ -0,0 +1,12 @@
+{
+ "request": {
+ "body": {
+ "count": "698"
+ }
+ },
+ "response": {
+ "body": {
+ "street": "USA"
+ }
+ }
+}
diff --git a/mocks-test/post/move/to/country/13/pi/1.json b/mocks-test/post/move/to/country/13/pi/1.json
new file mode 100755
index 0000000..4595917
--- /dev/null
+++ b/mocks-test/post/move/to/country/13/pi/1.json
@@ -0,0 +1,12 @@
+{
+ "request": {
+ "body": {
+ "pi": "123456"
+ }
+ },
+ "response": {
+ "body": {
+ "street": "NY"
+ }
+ }
+}
diff --git a/mocks-test/post/move/to/country/13/pi/2.json b/mocks-test/post/move/to/country/13/pi/2.json
new file mode 100755
index 0000000..b8ccfb3
--- /dev/null
+++ b/mocks-test/post/move/to/country/13/pi/2.json
@@ -0,0 +1,14 @@
+{
+ "request": {
+ "body": {
+ "pi": "j12"
+ }
+ },
+ "response": {
+ "body": {
+ "codigo": "123",
+ "mensagem": "Error :("
+ },
+ "httpStatus": "422"
+ }
+}
diff --git a/src/main/docker/Dockerfile b/src/main/docker/Dockerfile
new file mode 100644
index 0000000..9c4342e
--- /dev/null
+++ b/src/main/docker/Dockerfile
@@ -0,0 +1,17 @@
+FROM frolvlad/alpine-oraclejdk8:slim
+MAINTAINER "elemental-source"
+
+VOLUME /config
+VOLUME /data
+
+WORKDIR /
+
+EXPOSE 5000
+EXPOSE 9090
+
+COPY mock-api-*.jar app.jar
+ENTRYPOINT ["java", \
+ "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5000 -Djava.security.egd=file:/dev/./urandom", \
+ "-jar", \
+ "/app.jar", \
+ "--spring.config.location=file:/config/application.yml"]
\ No newline at end of file
diff --git a/src/main/java/br/com/elementalsource/mock/ApiApplication.java b/src/main/java/br/com/elementalsource/mock/ApiApplication.java
new file mode 100755
index 0000000..6a98ed9
--- /dev/null
+++ b/src/main/java/br/com/elementalsource/mock/ApiApplication.java
@@ -0,0 +1,34 @@
+package br.com.elementalsource.mock;
+
+import okhttp3.OkHttpClient;
+import org.apache.http.client.HttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.http.client.ClientHttpRequestFactory;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.web.client.RestTemplate;
+
+@SpringBootApplication
+@EnableCaching
+public class ApiApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ApiApplication.class, args);
+ }
+
+ @Bean
+ public RestTemplate restTemplate() {
+ HttpClient httpClient = HttpClientBuilder.create().build();
+ ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
+ return new RestTemplate(requestFactory);
+ }
+
+ @Bean
+ public OkHttpClient okHttpClient(){
+ return new OkHttpClient();
+ }
+
+}
diff --git a/src/main/java/br/com/elementalsource/mock/configuration/api/v1/controller/CaptureStateController.java b/src/main/java/br/com/elementalsource/mock/configuration/api/v1/controller/CaptureStateController.java
new file mode 100755
index 0000000..12c40ed
--- /dev/null
+++ b/src/main/java/br/com/elementalsource/mock/configuration/api/v1/controller/CaptureStateController.java
@@ -0,0 +1,57 @@
+package br.com.elementalsource.mock.configuration.api.v1.controller;
+
+import br.com.elementalsource.mock.configuration.api.v1.mapper.CaptureStateDto;
+import br.com.elementalsource.mock.configuration.service.CaptureStateService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.context.annotation.Bean;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/configuration/capture-state")
+public class CaptureStateController {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(CaptureStateController.class);
+
+ private final CaptureStateService service;
+
+ @Value("${captureState}")
+ private boolean captureState =true;
+
+ @Autowired
+ public CaptureStateController(CaptureStateService service) {
+ this.service = service;
+ }
+
+ @Bean
+ private CommandLineRunner onLoad() {
+ return args -> {
+ LOGGER.info("Application capture state: " + captureState);
+ if(captureState) {
+ this.service.enable();
+ }
+ };
+ }
+
+ @RequestMapping(method = RequestMethod.GET)
+ public ResponseEntity getCurrent() {
+ return ResponseEntity.ok().body(new CaptureStateDto(service.getCurrent()));
+ }
+
+ @RequestMapping(value = "/enable", method = RequestMethod.POST)
+ public ResponseEntity enable() {
+ return ResponseEntity.ok().body(new CaptureStateDto(service.enable()));
+ }
+
+ @RequestMapping(value = "/disable", method = RequestMethod.DELETE)
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void disable() {
+ service.delete();
+ }
+
+}
diff --git a/src/main/java/br/com/elementalsource/mock/configuration/api/v1/mapper/CaptureStateDto.java b/src/main/java/br/com/elementalsource/mock/configuration/api/v1/mapper/CaptureStateDto.java
new file mode 100755
index 0000000..457aa25
--- /dev/null
+++ b/src/main/java/br/com/elementalsource/mock/configuration/api/v1/mapper/CaptureStateDto.java
@@ -0,0 +1,35 @@
+package br.com.elementalsource.mock.configuration.api.v1.mapper;
+
+import br.com.elementalsource.mock.configuration.model.CaptureState;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.io.Serializable;
+import java.util.Optional;
+
+public class CaptureStateDto implements Serializable {
+
+ private final Boolean enabled;
+
+ @JsonCreator
+ public CaptureStateDto(@JsonProperty("enabled") Boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public CaptureStateDto(Optional captureMode) {
+ this(captureMode.map(o -> o.isEnabled()).orElse(false));
+ }
+
+ public CaptureStateDto(CaptureState captureState) {
+ this(Optional.ofNullable(captureState));
+ }
+
+ public Boolean isEnabled() {
+ return enabled;
+ }
+
+ public CaptureState toModel() {
+ return new CaptureState(enabled);
+ }
+
+}
diff --git a/src/main/java/br/com/elementalsource/mock/configuration/model/CaptureState.java b/src/main/java/br/com/elementalsource/mock/configuration/model/CaptureState.java
new file mode 100755
index 0000000..1d5ad15
--- /dev/null
+++ b/src/main/java/br/com/elementalsource/mock/configuration/model/CaptureState.java
@@ -0,0 +1,15 @@
+package br.com.elementalsource.mock.configuration.model;
+
+public class CaptureState {
+
+ private final Boolean enabled;
+
+ public CaptureState(Boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public Boolean isEnabled() {
+ return enabled;
+ }
+
+}
diff --git a/src/main/java/br/com/elementalsource/mock/configuration/repository/CaptureStateRepository.java b/src/main/java/br/com/elementalsource/mock/configuration/repository/CaptureStateRepository.java
new file mode 100755
index 0000000..a403a16
--- /dev/null
+++ b/src/main/java/br/com/elementalsource/mock/configuration/repository/CaptureStateRepository.java
@@ -0,0 +1,14 @@
+package br.com.elementalsource.mock.configuration.repository;
+
+import br.com.elementalsource.mock.configuration.model.CaptureState;
+
+import java.util.Optional;
+
+public interface CaptureStateRepository {
+
+ Optional getCurrent();
+
+ CaptureState save(CaptureState captureState);
+
+ void delete();
+}
diff --git a/src/main/java/br/com/elementalsource/mock/configuration/repository/impl/CaptureStateRepositoryImpl.java b/src/main/java/br/com/elementalsource/mock/configuration/repository/impl/CaptureStateRepositoryImpl.java
new file mode 100755
index 0000000..f02d591
--- /dev/null
+++ b/src/main/java/br/com/elementalsource/mock/configuration/repository/impl/CaptureStateRepositoryImpl.java
@@ -0,0 +1,40 @@
+package br.com.elementalsource.mock.configuration.repository.impl;
+
+import br.com.elementalsource.mock.configuration.model.CaptureState;
+import br.com.elementalsource.mock.configuration.repository.CaptureStateRepository;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Component;
+
+import java.util.Optional;
+
+import static java.util.Optional.empty;
+
+@Component
+@CacheConfig(cacheNames = "captureState")
+public class CaptureStateRepositoryImpl implements CaptureStateRepository {
+
+ private Optional captureState;
+
+ public CaptureStateRepositoryImpl() {
+ delete();
+ }
+
+ @Cacheable
+ public Optional getCurrent() {
+ return captureState;
+ }
+
+ @CacheEvict(allEntries = true)
+ public CaptureState save(CaptureState captureState) {
+ this.captureState = Optional.ofNullable(captureState);
+ return captureState;
+ }
+
+ @CacheEvict(allEntries = true)
+ public void delete() {
+ this.captureState = empty();
+ }
+
+}
diff --git a/src/main/java/br/com/elementalsource/mock/configuration/service/CaptureExecutor.java b/src/main/java/br/com/elementalsource/mock/configuration/service/CaptureExecutor.java
new file mode 100755
index 0000000..8722bfe
--- /dev/null
+++ b/src/main/java/br/com/elementalsource/mock/configuration/service/CaptureExecutor.java
@@ -0,0 +1,11 @@
+package br.com.elementalsource.mock.configuration.service;
+
+import br.com.elementalsource.mock.generic.model.Endpoint;
+import br.com.elementalsource.mock.generic.model.ExternalApiResult;
+
+@FunctionalInterface
+public interface CaptureExecutor {
+
+ void execute(ExternalApiResult apiResult, Endpoint endpoint);
+
+}
diff --git a/src/main/java/br/com/elementalsource/mock/configuration/service/CaptureStateService.java b/src/main/java/br/com/elementalsource/mock/configuration/service/CaptureStateService.java
new file mode 100755
index 0000000..229a5b9
--- /dev/null
+++ b/src/main/java/br/com/elementalsource/mock/configuration/service/CaptureStateService.java
@@ -0,0 +1,14 @@
+package br.com.elementalsource.mock.configuration.service;
+
+import br.com.elementalsource.mock.configuration.model.CaptureState;
+
+import java.util.Optional;
+
+public interface CaptureStateService {
+ Optional getCurrent();
+
+ CaptureState enable();
+
+ void delete();
+
+}
diff --git a/src/main/java/br/com/elementalsource/mock/configuration/service/impl/CaptureExecutorImpl.java b/src/main/java/br/com/elementalsource/mock/configuration/service/impl/CaptureExecutorImpl.java
new file mode 100755
index 0000000..6217e7c
--- /dev/null
+++ b/src/main/java/br/com/elementalsource/mock/configuration/service/impl/CaptureExecutorImpl.java
@@ -0,0 +1,25 @@
+package br.com.elementalsource.mock.configuration.service.impl;
+
+import br.com.elementalsource.mock.configuration.service.CaptureExecutor;
+import br.com.elementalsource.mock.generic.model.Endpoint;
+import br.com.elementalsource.mock.generic.model.ExternalApiResult;
+import br.com.elementalsource.mock.generic.service.EndpointBackupService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class CaptureExecutorImpl implements CaptureExecutor {
+
+ private final EndpointBackupService endpointBackupService;
+
+ @Autowired
+ public CaptureExecutorImpl(EndpointBackupService endpointBackupService) {
+ this.endpointBackupService = endpointBackupService;
+ }
+
+ public void execute(ExternalApiResult apiResult, Endpoint endpoint) {
+ if (apiResult.getUriConfiguration().isActiveBackup()) {
+ endpointBackupService.doBackup(endpoint);
+ }
+ }
+}
diff --git a/src/main/java/br/com/elementalsource/mock/configuration/service/impl/CaptureStateServiceImpl.java b/src/main/java/br/com/elementalsource/mock/configuration/service/impl/CaptureStateServiceImpl.java
new file mode 100755
index 0000000..8fd549b
--- /dev/null
+++ b/src/main/java/br/com/elementalsource/mock/configuration/service/impl/CaptureStateServiceImpl.java
@@ -0,0 +1,46 @@
+package br.com.elementalsource.mock.configuration.service.impl;
+
+import br.com.elementalsource.mock.configuration.model.CaptureState;
+import br.com.elementalsource.mock.configuration.service.CaptureStateService;
+import br.com.elementalsource.mock.infra.exception.impl.ApiApplicationException;
+import br.com.elementalsource.mock.configuration.repository.CaptureStateRepository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Optional;
+
+@Component
+public class CaptureStateServiceImpl implements CaptureStateService {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(CaptureStateServiceImpl.class);
+
+ private final CaptureStateRepository repository;
+
+ @Autowired
+ public CaptureStateServiceImpl(CaptureStateRepository repository) {
+ this.repository = repository;
+ }
+
+ public Optional getCurrent() {
+ return repository.getCurrent();
+ }
+
+ public CaptureState enable() {
+ return repository.save(Optional
+ .of(new CaptureState(true))
+ .map(old -> {
+ LOGGER.info("Backup activated");
+ return new CaptureState(true);
+ })
+ .orElseThrow(() -> new ApiApplicationException("cannot have an invalid capture state"))
+ );
+ }
+
+ public void delete() {
+ LOGGER.info("Backup deactivated");
+ repository.delete();
+ }
+
+}
diff --git a/src/main/java/br/com/elementalsource/mock/generic/api/v1/controller/GenericApiController.java b/src/main/java/br/com/elementalsource/mock/generic/api/v1/controller/GenericApiController.java
new file mode 100755
index 0000000..ad4bcf5
--- /dev/null
+++ b/src/main/java/br/com/elementalsource/mock/generic/api/v1/controller/GenericApiController.java
@@ -0,0 +1,94 @@
+package br.com.elementalsource.mock.generic.api.v1.controller;
+
+import br.com.elementalsource.mock.generic.service.GenericApiService;
+import br.com.elementalsource.mock.infra.component.JsonFormatter;
+import br.com.elementalsource.mock.infra.component.RequestFormatter;
+import br.com.elementalsource.mock.generic.api.v1.mapper.RequestMapper;
+import com.google.gson.Gson;
+import com.google.gson.JsonParseException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Optional;
+
+@RestController
+public class GenericApiController {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(GenericApiController.class);
+
+ private final GenericApiService genericApiService;
+ private final RequestMapper requestMapper;
+ private final JsonFormatter jsonFormatter;
+ private final RequestFormatter requestFormatter;
+
+ @Autowired
+ public GenericApiController(GenericApiService genericApiService, RequestMapper requestMapper,
+ JsonFormatter jsonFormatter, RequestFormatter requestFormatter) {
+ this.genericApiService = genericApiService;
+ this.requestMapper = requestMapper;
+ this.jsonFormatter = jsonFormatter;
+ this.requestFormatter = requestFormatter;
+ }
+
+ private void logRequest(final HttpServletRequest request, final Optional