{"id":18015563,"url":"https://github.com/nomemory/serverneat","last_synced_at":"2025-03-26T18:31:18.534Z","repository":{"id":48537755,"uuid":"255720445","full_name":"nomemory/serverneat","owner":"nomemory","description":"A Kotlin DSL for creating mock servers - using MockNeat for generating data","archived":false,"fork":false,"pushed_at":"2021-07-21T03:38:28.000Z","size":85,"stargazers_count":21,"open_issues_count":11,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-22T06:31:48.469Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nomemory.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-04-14T20:38:08.000Z","updated_at":"2024-08-09T09:02:32.000Z","dependencies_parsed_at":"2022-09-03T07:22:18.633Z","dependency_job_id":null,"html_url":"https://github.com/nomemory/serverneat","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomemory%2Fserverneat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomemory%2Fserverneat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomemory%2Fserverneat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomemory%2Fserverneat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nomemory","download_url":"https://codeload.github.com/nomemory/serverneat/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245712648,"owners_count":20660276,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-30T04:14:25.397Z","updated_at":"2025-03-26T18:31:18.243Z","avatar_url":"https://github.com/nomemory.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ServerNeat\n\n## Introduction\n\n*ServerNeat* is (~not another~) a Kotlin Web Server for mocking and stubbing Rest APIs.\n\nIt provides and easy to use DSL and seamless integration with [MockNeat](http://www.mockneat.com) for generating dynamic json responses.\n\n*ServerNeat* can be used as standalone application, capable of loading, compiling and evaluating `kts` scripts, or as a Kotlin/Java library.   \n\n## Building the stand-alone mock server\n\nBy executing the `application` task, a a (fat) stand-alone jar is created in the `build\\libs` folder:\n\nGradle:\n```groovy\ngradle application\n```\n\nRunning the server:\n\n```\njava -jar serverneat-all-1.0-SNAPSHOT.jar -f \u003cpath-to-kts-script\u003e\n``` \n\nNote: in the `examples\\` folder there are a few `.kts` scripts that can be used for testing.\n\n## Features\n\nThe server supports the following types of responses:\n\n| ResponseType      |   Description  |\n| ------------      |   ----------- |\n| PlainText         | Responds to the HTTP by returning simple `String` values as the response body. |\n| File Content      | Responds to the request reading the content of a file and returning it as `String`. It can be useful when you want to separate the response bodies from the configuration. |\n| Resource Content  | Similar to `File Content`, except the files are read as Resources from the `resources` folder. It's particularly useful when you don't run **serverneat** as standalone application but you use it as a \"library\". |\n| File Download     | Useful when you want to emulate a route that is allowing the user to download a file. |\n| JSON Content      | Allows you to generate JSON in an instant using a nice DSL and www.mockneat.com integration. |    \n\n## Examples\n\nCheck the `examples` folder.\n\n### Plain text response - Hello world\n\n```kotlin\nimport net.andreinc.serverneat.server.server\n\nserver {\n\n    httpOptions {\n        host = \"localhost\"\n        port = 8081\n    }\n\n    globalHeaders {\n        header(\"Content-Type\", \"application/text\")\n    }\n\n    routes {\n        get {\n            path = \"/plainText\"\n            response {\n                header(\"plain\", \"text\")\n                statusCode = 200\n                plainText {\n                    value = \"Hello World!\"\n                }\n            }\n        }\n    }\n\n\n}.start()\n```\n\n### Json Response (Simple)\n\n```kotlin\nimport net.andreinc.serverneat.mockneat.extension.obj\nimport net.andreinc.serverneat.server.server\n\nserver {\n\n    httpOptions {\n        host = \"localhost\"\n        port = 8081\n    }\n\n    globalHeaders {\n        header(\"Content-Type\", \"application/json\")\n    }\n\n    routes {\n        get {\n            path = \"/user/100\"\n            response {\n                header(\"plain\", \"text\") // Adding a custom header to the response\n                statusCode = 200\n                json {\n                    value = obj {\n                        \"firstName\" const \"Mike\"\n                        \"lastName\" const \"Smith\"\n                        \"someFiles\" const arrayOf(\"file1.txt\", \"file2.txt\")\n                        \"anotherObject\" value obj {\n                            \"someData\"  const \"someValue\"\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n\n}.start()\n```\n\nPS: When creating an inner structure it's important to use `value` instead of `const`. \n\nCalling the service `curl localhost:8081/user/100`:\n\n```\n{\n  \"firstName\": \"Mike\",\n  \"lastName\": \"Smith\",\n  \"anotherObject\": {\n      \"someData\": {}\n  },\n  \"someFiles\": [\n    \"file1.txt\",\n    \"file2.txt\"\n  ]\n}\n```\n\nPS: When creating an inner structure it's important to use `value` instead of `const`. \n\n### Json Response (Dynamic - using [MockNeat](https://www.mockneat.com/))\n\nThe value object can be any [MockUnit](https://www.mockneat.com/tutorial/#everything-is-a-mockunitt).  \n\n```kotlin\nimport net.andreinc.mockneat.unit.address.Cities.cities\nimport net.andreinc.mockneat.unit.financial.CreditCards.creditCards\nimport net.andreinc.mockneat.unit.time.LocalDates.localDates\nimport net.andreinc.mockneat.unit.user.Genders.genders\nimport net.andreinc.mockneat.unit.user.Names.names\nimport net.andreinc.serverneat.mockneat.extension.obj\nimport net.andreinc.serverneat.server.server\n\nserver {\n\n    httpOptions {\n        host = \"localhost\"\n        port = 8081\n    }\n\n    globalHeaders {\n        header(\"Content-Type\", \"application/json\")\n    }\n\n    routes {\n        get {\n            path = \"/users\"\n            response {\n                statusCode = 200\n                json {\n                    persistent = true // generated data will be stored in the file \"usersList.json\"\n                    file = \"dyanmic-example/usersList.json\"\n                    value = obj {\n                        \"users\" value obj {\n                            \"firstName\" value names().first()\n                            \"lastName\" value names().last()\n                            \"gender\" value genders()\n                            \"financialInformation\" value obj {\n                                \"creditCard1\" value creditCards().visa()\n                                \"creditCard2\" value creditCards().amex()\n                            }\n                            \"visits\" value obj {\n                                \"time\" value localDates().thisYear()\n                                \"city\" value cities().capitalsEurope()\n                            }.list(5)\n                        }.list(50)\n                    }\n                }\n            }\n        }\n    }\n}.start()\n```\n\nAnd the reponse will be\n\n```json\n{\n    \"users\": [\n        {\n            \"firstName\": \"Tommie\",\n            \"lastName\": \"Pecinousky\",\n            \"visits\": [\n                {\n                    \"city\": \"Copenhagen\",\n                    \"time\": {\n                        \"year\": 2020,\n                        \"month\": 1,\n                        \"day\": 7\n                    }\n                },\n                {\n                    \"city\": \"Monaco\",\n                    \"time\": {\n                        \"year\": 2020,\n                        \"month\": 11,\n                        \"day\": 13\n                    }\n                },\n                {\n                    \"city\": \"Tallinn\",\n                    \"time\": {\n                        \"year\": 2020,\n                        \"month\": 10,\n                        \"day\": 22\n                    }\n                },\n                {\n                    \"city\": \"Sarajevo\",\n                    \"time\": {\n                        \"year\": 2020,\n                        \"month\": 3,\n                        \"day\": 7\n                    }\n                },\n                {\n                    \"city\": \"Athens\",\n                    \"time\": {\n                        \"year\": 2020,\n                        \"month\": 12,\n                        \"day\": 15\n                    }\n                }\n            ],\n            \"financialInformation\": {\n                \"creditCard2\": \"340529111074115\",\n                \"creditCard1\": \"4647171048830798\"\n            },\n            \"gender\": \"Female\"\n        },\n        {\n            \"firstName\": \"Sid\",\n            \"lastName\": \"Falge\",\n            \"visits\": [\n                {\n                    \"city\": \"Berlin\",\n                    \"time\": {\n                        \"year\": 2020,\n                        \"month\": 2,\n                        \"day\": 22\n                    }\n                },\n                {\n                    \"city\": \"Brussels\",\n                    \"time\": {\n                        \"year\": 2020,\n                        \"month\": 1,\n                        \"day\": 27\n                    }\n                },\n                {\n                    \"city\": \"Athens\",\n                    \"time\": {\n                        \"year\": 2020,\n                        \"month\": 12,\n                        \"day\": 28\n                    }\n                },\n                {\n                    \"city\": \"San Marino\",\n                    \"time\": {\n                        \"year\": 2020,\n                        \"month\": 10,\n                        \"day\": 23\n                    }\n                },\n                {\n                    \"city\": \"Stockholm\",\n                    \"time\": {\n                        \"year\": 2020,\n                        \"month\": 5,\n                        \"day\": 12\n                    }\n                }\n            ],\n            \"financialInformation\": {\n                \"creditCard2\": \"373802757435803\",\n                \"creditCard1\": \"4332758675303071\"\n            },\n            \"gender\": \"Male\"\n        }\n    /// and so on\n    ]\n}\n```\n\n*and son on for the rest of the users*\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnomemory%2Fserverneat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnomemory%2Fserverneat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnomemory%2Fserverneat/lists"}