Mockaco
website·Indexed 30 days ago
https://natenho.github.io/Mockaco/A tool to simplify the setup and execution of API mocks featuring Pure C# scripting, built-in fake data generation, and support for stateful mocks. It includes capabilities for mocking binary/raw and XML responses, request matching, chaos engineering, and a generator for creating mock templates from specifications like OpenAPI.
What's inside Mockaco
- Mockaco simplifies the setup and execution of API mocks. It allows developers to add dynamic content to mocks using pure C# scripting, eliminating the need to learn a proprietary language or specific API for mock logic. Additionally, it includes built-in fake data generation to streamline the creation of mock responses.
Understand Mockaco request matching logic
When a request is received, Mockaco determines which mock file to use based on the following process:
- Mock files are searched in alphabetical order.
- The request is compared against the
requestobject criteria in each file. - The first match that meets the criteria is selected. If multiple mocks match, those with a
conditionare prioritized. - If no match is found, Mockaco returns an HTTP 501 (Not Implemented) response containing a list of possible file parsing errors.
Create a mock response in Mockaco
To create a mock in Mockaco, create a JSON file within theMocksfolder. The file defines a request/response template: when the server receives a request matching the specified method and route, it will return the defined status and response body.{ "request": { "method": "GET", "route": "ping" }, "response": { "status": "OK", "body": { "response": "pong" } } }Query the request body using JSONPath
For complex objects, use theSelectToken(returns a singleJToken) andSelectTokens(returns a collection ofJTokens) methods onRequest.Bodyto filter and traverse data using JSONPath. If a token is not found, these methods returnnull.{ "request": { "method": "POST", "route": "/json_path" }, "response": { "body": { "Manufacturer": "<#= Request.Body.SelectToken("Manufacturers[0].Name") #>", "Price": "<#= Request.Body.SelectToken("Manufacturers[0].Products[0].Price") #>", "ProductName": "<#= Request.Body.SelectToken("Manufacturers[1].Products[0].Name") #>", "AcmeManufacturer": <#= Request.Body.SelectToken("$.Manufacturers[?(@.Name == 'Acme Co')]") #>, "FilteredProducts": <#= JsonConvert.SerializeObject(Request.Body.SelectTokens("$..Products[?(@.Price >= 50)].Name")) #> } } }Mock XML responses using request data
Mockaco can parse XML request payloads and make their elements available for use in response or callback templates. To ensure correct parsing, the
Content-Typeheader must be set toapplication/xmlortext/xml.Accessing XML Data
Use the following syntax within response templates to access request body elements:
- Simple elements (no attributes): Access directly by name. Example:
Request.Body["root"]?["theSongName"] - Elements with attributes (text content): Use the
#textkey to get the inner text. Example:Request.Body["root"]?["theAlbum"]?["#text"] - Element attributes: Use the
@prefix followed by the attribute name. Example:Request.Body["root"]?["theAlbum"]?["@year"]
{ "request": { "method": "POST", "route": "songs" }, "response": { "status": "OK", "headers": { "Content-Type": "application/xml" }, "body": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<song>\n <name><#=Request.Body[\"root\"]? [\"theSongName\"]#></name>\n <album>\n <name><#=Request.Body[\"root\"]? [\"theAlbum\"]? [\"#text\"]#></name>\n <year><#=Request.Body[\"root\"]? [\"theAlbum\"]? [\"@year\"]#></year>\n </album>\n</song>" } }- Simple elements (no attributes): Access directly by name. Example:
Run Mockaco from source code
Clone the repository and run the project using the .NET CLI. If the--urlsparameter is not provided during execution, a random local port will be chosen.$ git clone https://github.com/natenho/Mockaco.git $ cd Mockaco\src\Mockaco $ dotnet runGenerate mock templates from a specification
Use themockaco generatecommand to automatically create mock templates based on a provided specification file or URL. You must specify the provider (e.g.,openapi) to tell Mockaco how to parse the specification.mockaco generate [url/path to the specification] --provider=[provider name] # Example: Generating mocks from the Petstore OpenAPI specification mockaco generate https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json --provider=openapiInstall and run Mockaco using .NET CLI
Install Mockaco as a global .NET tool. You can specify a custom URL using the--urlsparameter; otherwise, a random local port will be assigned automatically.$ dotnet tool install -g mockaco $ mockaco --urls "http://localhost:5000"Simulate stateful API behavior using the Global object
Because theGlobalobject is shared across all requests, you can store a variable in one mock endpoint and retrieve it in another. This is useful for simulating stateful interactions (e.g., a 'store' endpoint that sets a value and a 'retrieve' endpoint that reads it).// Mock 1: Store the variable { "request": { "method": "GET", "route": "store" }, "response": { "status": "OK", "body": { "response": "This request stores a variable" } } <# Global["my-custom-variable"] = "hello!"; #> } // Mock 2: Retrieve the variable { "request": { "method": "GET", "route": "retrieve" }, "response": { "status": "OK", "body": { "response": "The variable is <#=Global["my-custom-variable"] #>" } } }Generate fake data using the Faker facade
Mockaco provides aFakerfacade object that can be used within script tags (<#= ... #>) to generate random fake data for response bodies. Common categories includeName,Company, andAddress.{ "request": { "method": "GET" }, "response": { "status": "OK", "headers": { "Content-Type": "application/json" }, "body": { "name": "<#= Faker.Name.FullName() #>", "company": "<#= Faker.Company.CompanyName() #>", "city": "<#= Faker.Address.City() #>" } } }Extract data from the request body as a dictionary
The
Request.Bodyproperty is aJTokenobject containing the parsed request body. Mockaco supportsapplication/json,application/xml,text/xml,text/plain,application/x-www-form-urlencoded, andmultipart/form-datacontent types.You can query the body using dictionary-style indexing. Because missing keys return
null, it is recommended to use the C# null-conditional operator (?).{ "response": { "body": { "id": "<#=Request.Route["id"] #>", "name": "<#=Request.Body["songs"]?[0]?["name"] #>", "album": { "name": "<#=Request.Body["songs"]?[0]?["album"]?["name"] #>", "year": "<#=Request.Body["songs"]?[0]?["album"]?["year"] #>" } } } }Manage global state in Mockaco mocks
Mockaco allows persisting state using aGlobalobject, which consists of simple global variables stored in memory and accessible across all active mocks. These variables can hold any object, such as boolean flags, strings, or request payloads. If a global variable has not been initialized, it returnsnull.// Setting a global variable (wrapped in <# #>) <# Global["my-custom-variable"] = "my-custom-state"; #> // Retrieving a global variable (wrapped in <#= #>) <#=Global["my-custom-variable"]#>