# Documentation - [General Overview](#general-overview) - [Main Concepts](#main-concepts) - [NetWork Exchange](#network-exchange) - [Request](#request) - [Response](#response) - [Type of response](#type-of-response) - [Espresso Martini for iOS & macOS](#espressomartini-for-ios--macos) - [Installation](#installation) - [Configuring the Mock Server](#configuring-the-mock-server) - [Interacting with the server](#interacting-with-the-server) - [Building a network exchange](#building-a-network-exchange) - [EspressoMartini CLI](#espressomartini-cli) - [Installing the CLI](#installing-the-cli) - [Using the CLI](#using-the-cli) - [Setting up the network exchanges](#setting-up-the-network-exchanges) - [Configuring the CLI](#configuring-the-cli) ## General Overview `EspressoMartini` is an `HTTP` mock server powered by [Vapor](https://github.com/vapor/vapor) that allows to simulate full `HTTP` responses including custom headers, status codes and various type of `Data`. It is built with the goal of integrating in in your iOS and macOS applications, but provides a CLI that allows running the server locally so you can have all the benefits regardless of what application or service you are trying to build. ## Main Concepts ### Network Exchange A `NetworkExchange` object is the main entity in `EspressoMartini`. Each `NetworkExchange` represents a pair of [Request](#request) object and an array of desired [Response](#response) objects. ### Request A `Request` is an object that represents the request that the server should intercept. It is made of a path and method. ### Response A `Response` is an object that represents the response that the server should return. It contains the status code the server should return, the headers you want returned, the [type of response](#type-of-response) data, and the delay the server should wait before returning the response. #### Type of response The server can return different types of responses. Specifically: 1. `empty`: Suitable for HTTP requests with no responses, like `HTTPResponseStatus.noContent` 1. `data(_ data: Data)`: The response is some `Data` you would like to return. In this case the `Content-Type` header should be set manually. 1. `string(_ value: String)`: The response is a simple `String`. 1. `json(_ value: Encodable, encoder: JSONEncoder = JSONEncoder())`: A helper over `Data` where the server will encode the encodable object and return it as a JSON. This will automatically set (or override) the `Content-Type`. 1. `fileContent(pathToFile: String)`: Data to read off a file. The file path **SHOULD** contain the extension as it will be used to set the `Content-Type` header. ## EspressoMartini for iOS & macOS ### Installation EspressoMartini support `SwiftPM`. Open your `Package.swift` file and add the following as your dependency. ```swift dependencies: [ .package(url: "https://github.com/TheInkedEngineer/Espresso-Martini", from: "1.0.0") ] ``` Then add the following to your target's dependency: ```swift targets: [ .target( name: "MyTarget", dependencies: [ .product(name: "https://github.com/TheInkedEngineer/Espresso-Martini", package: "Espresso-Martini") ] ) ] ``` ### Configuring the Mock Server The mock server is configured using an object that conforms to `ServerConfigurationProvider`. `EspressoMartini` offers two built in objects: - `MockServer.SimpleConfiguration(networkExchanges:)` which leverages the protocol's defaults and requires only the [NetworkExchange](#network-exchange) array to start your mock server. - `MockServer.Configuration(networkExchanges:environment:hostname:port:delay:logLevel:)` which offers more flexibility to set your own properties. Example: ```swift let mockServer = MockServer() try server.configure( using: MockServer.SimpleConfiguration( networkExchanges: [ // Some network exchange objects. ] ) ) ``` ### Interacting with the server The mock server offers three more methods: - `run()` which starts and runs the server of the provided hostname and port. - `stop()` which stops the running instance of the server. - `restart(configuration:)` which stops and runs the server again with the new configuration. ### Building a network exchange The `NetworkExchange` is made of: - A [Request](#request): - An `HTTPMethod` - A `Path`; An array of `Strings` where each string represents a path component. - Include `*` in any position and the value of that field will be discarded. This is useful when the path includes an `ID`. `/api/*/users` will be matched by `/api/v1/users`, `/api/v2/users` and anything similar. - Include `**` and any string at this position or later positions will be matched in the request. `/api/**` will be matched by `/api/v1/users`, `/api/users/notes` and anything that starts with `/api`. - A [Response](#response): - A `HTTPResponseStatus` - A list of headers to include in the response. - The delay before the answer is returned. If this value is set it will override the global delay value. If this value is `nil` the answer will be returned after the global delay. > A network exchange can have more than one response. This is handy to simulate scenarios like `polling` and `error+retry+recover`. When a network exchange has more than 1 answer, the mock server will return the `min(nth response, array.count - 1)` where `n` is the number of request to that same path. ## EspressoMartini CLI You do not need an iOS or macOS application to benefit from `EspressoMartini`. ### Installing the CLI 1. Clone the repo `git clone git@github.com:TheInkedEngineer/Espresso-Martini.git` 1. `cd Espresso-Martini` 1. `make` -- you might need to run it with `sudo` privileges. ### Configuring the CLI The server is configured using a `configuration.json` file. This file can have another name, you can point to it using `--configuration ` option. The server configuration is optional. If not provided all default values will be used. However, if you opt to include some configuration, `hostname` and `port` become mandatory. Everything else remains optional. Example: ```json { "hostname": "127.0.0.1", "port": 3000, "delay": 1, "log_level": "CRITICAL" } ``` - LogLevel can have the following values: - "TRACE" - "DEBUG" - "INFO" - "NOTICE" - "WARNING" - "ERROR" - "CRITICAL" ### Setting up the network exchanges The network exchanges are setup without any code by using `JSON` files. Each folder name after the root folder (named `network-exchange` but customisable using the `--requests-folder ` option) represents a component of the path. The last folder should be a method name and it will not be included in the path. Each method folder should contain a `configuration.json` file and 0 or more response files that can be anything from images, to `json` to any `Data` really. Example: ``` ├── network-exchanges │ ├── api │ │ ├── v1 │ │ │ ├── user │ │ │ │ ├── POST │ | | | | |── configuration.json │ | | | | |── response.json │ | | | | |── response2.json │ │ │ │ ├── DELETE │ | | | | |── configuration.json ``` This will generate 2 NetworkExchanges. One with a `POST` and another `DELETE` request, both to `api/v1/user` endpoint. Since the request requirements are generated from the folder structure, the `configuration.json` file is an array of responses consisting of one ore more responses. Example: ```json [ { "status_code": 400, "response_file": "error.json", "delay": 2 }, { "status_code": 204, "headers": { "key": "value" } } ] ``` ### Using the CLI - `espressomartini run` -- Runs the server with the list of all network exchanges. - `--configuration ` argument points to the name of the configuration file. - `--requests-folder ` argument points to the name of the folder where the request reside. Defaults to `networkExchanges`. - `espressomartini endpoints` -- Fetches the list of all the endpoints - `--requests-folder ` argument points to the name of the folder where the request reside. Defaults to `networkExchanges`.