{"id":20537561,"url":"https://github.com/jonathangiles/teenyhttpd","last_synced_at":"2025-08-08T01:13:27.022Z","repository":{"id":57737277,"uuid":"257141960","full_name":"JonathanGiles/TeenyHttpd","owner":"JonathanGiles","description":"TeenyHttpd is a HTTP server written in Java.","archived":false,"fork":false,"pushed_at":"2024-07-24T02:09:54.000Z","size":260,"stargazers_count":17,"open_issues_count":2,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-27T21:11:31.725Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JonathanGiles.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-20T01:36:53.000Z","updated_at":"2024-10-22T21:51:45.000Z","dependencies_parsed_at":"2024-01-22T23:47:46.882Z","dependency_job_id":"7c3091aa-07b7-4058-bd3f-30a7202b69a5","html_url":"https://github.com/JonathanGiles/TeenyHttpd","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/JonathanGiles%2FTeenyHttpd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JonathanGiles%2FTeenyHttpd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JonathanGiles%2FTeenyHttpd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JonathanGiles%2FTeenyHttpd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JonathanGiles","download_url":"https://codeload.github.com/JonathanGiles/TeenyHttpd/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248840371,"owners_count":21169978,"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-11-16T00:41:36.818Z","updated_at":"2025-04-14T07:36:57.002Z","avatar_url":"https://github.com/JonathanGiles.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TeenyHttpd\n\n\u003cpicture\u003e\u003cimg src=\"https://img.shields.io/maven-central/v/net.jonathangiles.tools/teenyhttpd?color=blue\" /\u003e\u003c/picture\u003e\n\u003cpicture\u003e\u003cimg src=\"https://img.shields.io/github/repo-size/JonathanGiles/TeenyHttpd?color=blue\" /\u003e\u003c/picture\u003e\n\u003cpicture\u003e\u003cimg src=\"https://img.shields.io/github/license/JonathanGiles/TeenyHttpd?color=blue\" /\u003e\u003c/picture\u003e\n\u003cpicture\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/JonathanGiles/TeenyHttpd/main.yml?color=blue\" /\u003e\u003c/picture\u003e\n\nTeenyHttpd is an extremely basic HTTP server, as well as an extremely basic application stack (similar to Spring). It is implemented in plain old Java with no runtime dependencies, making it lightweight and applicable in situations where a basic, small HTTP server and application stack is all that is required.\n\n## Getting Started\n\nTo make use of TeenyHttpd in your project, just add the following Maven dependency to your build:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.jonathangiles.tools\u003c/groupId\u003e\n    \u003cartifactId\u003eteenyhttpd\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.5\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Reference Documentation\n\nThe TeenyHttpd JavaDoc for the current code in this repo is available [here](https://teenyhttpd.z22.web.core.windows.net/). This may be different than the JavaDoc for the most recent release.\n\n## TeenyHttpd Examples\n\nThe following examples demonstrate how to use TeenyHttpd to serve static content, as well as how to programmatically define routes. Further down this page are examples of how to use the TeenyApplication application stack.\n\n### Serving Static Content\n\nIf you already have content you want to serve, you can simply place the latest `teenyhttpd-x.y.z.jar` file in the same \ndirectory as your content, and then run the following command:\n\n```bash\njava -jar teenyhttpd-x.y.z.jar\n```\n\nThis will start a server on port 80, and will serve all content from the directory that the JAR file is located in. \nThere is a `--help` parameter that will give some useful guidance on how to customize the server, which is shown below:\n\n``` \nUsage: java -jar teenyhttpd.jar [options]\n\nOptions:\n  --port=80\n      The port to run the server on\n  --dir=.\n      The root directory to serve files from\n  --path=/\n      The path to serve files from (e.g. '/blah' for http://localhost/blah\n  -h, --help\n      Print this help message and exit\n```\n\n### Programmatically Serving Files from a Webroot\n\nBy default, with the configuration below, TeenyHttpd will serve files from within the `/src/main/resources/webroot` \ndirectory, and they will be accessible from the root path (for example, a GET request for `http://localhost/index.html` will look in the root of the `webroot` directory for an `index.html` file):\n\n```java\nfinal int PORT = 80;\nTeenyHttpd server = new TeenyHttpd(PORT);\nserver.addFileRoute(\"/\");\nserver.start();\n```\n\nYou can change the path to the webroot directory by passing in a `File` object to the constructor:\n\n```java\nfinal int PORT = 80;\nTeenyHttpd server = new TeenyHttpd(PORT);\nserver.addFileRoute(\"/\", new File(\"/path/to/webroot\"));\nserver.start();\n```\n\nYou can also change the request path that is used to access the webroot directory:\n\n```java\nfinal int PORT = 80;\nTeenyHttpd server = new TeenyHttpd(PORT);\nserver.addFileRoute(\"/files\", new File(\"/path/to/webroot\"));\nserver.start();\n```\n\n### Programmatic Routes\n\nYou can also programmatically define routes to serve. For example, the following code will serve a `Hello world!` \nwhen a GET request is received for the `/hello` path:\n\n```java\nfinal int PORT = 80;\nTeenyHttpd server = new TeenyHttpd(PORT);\nserver.addStringRoute(\"/hello\", request -\u003e \"Hello world!\");\nserver.start();\n```\n\n#### HTTP Methods\n\nThe TeenyHttpd server supports all HTTP methods. There is an `addGetRoute` method for the commonly-used GET method, \nas well as a generic `addRoute` method that can be used to specify any HTTP method. For example, the following code\nwill serve a `Hello world!` when a GET request is received for the `/hello` path, but will return a 404 for any other\nHTTP method:\n\n```java\nfinal int PORT = 80;\nTeenyHttpd server = new TeenyHttpd(PORT);\nserver.addGetRoute(\"/hello\", request -\u003e \"Hello world!\");\nserver.start();\n```\n\nFor all other HTTP methods, you can use the `addRoute` method. For example, the following code will serve a `Hello world!`\nwhen a POST request is received for the `/hello` path, but will return a 404 for any other HTTP method:\n\n```java\nfinal int PORT = 80;\nTeenyHttpd server = new TeenyHttpd(PORT);\nserver.addRoute(HttpMethod.POST, \"/hello\", request -\u003e \"Hello world!\");\nserver.start();\n```\n\n### Path Parameters\n\nIt is possible to specify path parameters in the path that is registered by using the `:` character. For example, \nthe following code will serve a response of `User ID: 123` when a GET request is received for the `/user/123/details`\n\n```java\nserver.addGetRoute(\"/user/:id/details\", request -\u003e {\n    String id = request.getPathParams().get(\"id\");\n    return Response.create(StatusCode.OK, \"User ID: \" + id);\n});\n```\n\n### Query Parameters\n\nIt is possible to access query parameters in the request. For example, the following code will print out all query\nparameters that are received in a GET request on the route `/QueryParams`:\n\n```java\nserver.addGetRoute(\"/QueryParams\", request -\u003e {\n    request.getQueryParams().forEach((key, value) -\u003e System.out.println(key + \" = \" + value));\n    return StatusCode.OK.asResponse();\n});\n```\n\nFor example, calling the route above with the `http://localhost/queryParams?test=true\u0026foo=bar` URL will print out the following:\n\n```\ntest = true\nfoo = bar\n```\n\n## Server-Sent Events\n\nTeenyHttpd supports Server-Sent Events (SSE). To use this feature, you need to use the `addServerSentEventRoute` method,\nwith a `ServerSentEventHandler`. For example, the following code will send a message to the client every second:\n\n```java\nfinal int PORT = 80;\nTeenyHttpd server = new TeenyHttpd(PORT);\nserver.addServerSentEventRoute(\"/events\", ServerSentEventHandler.create(sse -\u003e new Thread(() -\u003e {\n    int i = 0;\n    while (sse.hasActiveConnections()) {\n        sse.sendMessage(new ServerSentEventMessage(\"Message \" + i++, \"counter\"));\n        threadSleep(1000);\n    }\n}).start()));\nserver.start();\n```\n\nIf more than one user connects to the same /events topic, they will share the same state, each getting the same value \nfor `i` at the same time. If you want to customise the response per user (for example, based on a path parameter or\nquery parameter), you can use the message generator feature:\n\n```java\nServerSentEventHandler sse = ServerSentEventHandler.create((ServerSentEventHandler _sse) -\u003e {\n    // start a thread and send messages to the client(s)\n    new Thread(() -\u003e {\n        // all clients share the same integer value, but they get a custom message based\n        // on the path parameter for :username\n        AtomicInteger i = new AtomicInteger(0);\n\n        while (_sse.hasActiveConnections()) {\n            _sse.sendMessage(client -\u003e {\n                String username = client.getPathParams().get(\"username\");\n                return new ServerSentEventMessage(\"Hello \" + username + \" - \" + i, \"counter\");\n            });\n            i.incrementAndGet();\n            threadSleep(1000);\n        }\n    }).start();\n});\nserver.addServerSentEventRoute(\"/sse/:username\", sse);\n```\n\nThe above samples assume that you start a thread when there are active connections, to send messages to connected \nclients at a regular interval. Another approach is to just have a ServerSentEventHandler that sends messages to\nconnected clients when a message is received. For example, the following code will send a message to all clients \nthat are connected to the `/messages` topic, when a message is posted to `/message`:\n\n```java\nfinal int PORT = 80;\nTeenyHttpd server = new TeenyHttpd(PORT);\nServerSentEventHandler chatMessagesEventHandler = ServerSentEventHandler.create();\nserver.addServerSentEventRoute(\"/messages\", chatMessagesEventHandler);\nserver.addRoute(Method.POST, \"/message\", request -\u003e {\n    String message = request.getQueryParams().get(\"message\");\n    if (message != null \u0026\u0026 !message.isEmpty()) {\n        chatMessagesEventHandler.sendMessage(message);\n    }\n    return StatusCode.OK.asResponse();\n});\n```\n\nFor a complete example, check out the [ChatServer](https://github.com/JonathanGiles/TeenyHttpd/blob/master/src/test/java/net/jonathangiles/tools/teenyhttpd/chat/ChatServer.java) \ndemo application, that demonstrates how to use Server-Sent Events to create a simple chat server.\n\n### Stopping TeenyHttpd\n\nYou stop a running instance as follows:\n\n```java\nfinal int PORT = 80;\nTeenyHttpd server = new TeenyHttpd(PORT);\nserver.start();\n\n// some time later...\nserver.stop();\n```\n\n## TeenyApplication Examples\n\nWhat was shown above is the 'low-level' APIs of TeenyHttpd. However, TeenyHttpd also includes a simple application stack called TeenyApplication. This application stack is similar to Spring, but is much simpler and lighter weight.\n\nA basic application starts as follows:\n\n```java\npublic class RestApp {\n    public static void main(String[] args) {\n        System.setProperty(\"server.port\", \"80\");\n        TeenyApplication.start(RestApp.class);\n    }\n}\n```\n\nOf course, this isn't all that useful, as we have not defined any routes. Let's update the code above to do that now:\n\n```java\npublic class RestApp {\n    public static void main(String[] args) {\n        System.setProperty(\"server.port\", \"80\");\n        TeenyApplication.start(RestApp.class);\n    }\n\n    @Post(\"/message\")\n    public void message(@QueryParam(\"message\") String message) {\n        // do something with the message that was posted to the /message route\n    }\n\n    @Get(\"/products\")\n    public Collection\u003cProduct\u003e get() {\n        // return a collection of products\n    }\n\n    @Get(\"/product/:id\")\n    public TypedResponse\u003cProduct\u003e getProduct(@PathParam(\"id\") int id) {\n        // Do something like this, by taking the 'id' path parameter and looking up a product\n        Product product = productMap.get(id);\n        if (product != null) return TypedResponse.ok(product);\n        return TypedResponse.notFound();\n    }\n}\n```\n\nAs you might expect, there are annotations for many of the common use cases:\n\n* HTTP Methods: `@Get`, `@Post`, `@Put`, `@Delete`, `@Patch`\n* Path Parameters: `@PathParam`\n* Query Parameters: `@QueryParam`\n* Headers: `@RequestHeader`\n* Request Body: `@RequestBody`\n* Server-Sent Events: `@ServerEvent`\n\n### Server-Sent Events\n\nSimply define the handler and give it a name, if no name is specified then the name of the method will be used instead.\n\n```java\n@ServerEvent(value = \"/messages\", name = \"messages\")\npublic ServerSentEventHandler chatMessages() {\n    return ServerSentEventHandler.create();\n}\n```\n\nUse it directly anywhere:\n\n```java\n@Post(\"/message\")\npublic void message(@QueryParam(\"message\") String message,\n                    @EventHandler(\"messages\") ServerSentEventHandler chatMessagesEventHandler) {\n    chatMessagesEventHandler.sendMessage(message);\n}\n```\n\nSimilar to the [ChatServer](https://github.com/JonathanGiles/TeenyHttpd/blob/master/src/test/java/net/jonathangiles/tools/teenyhttpd/chat/ChatServer.java) demo application linked above (which simply uses TeenyHttpd), [there is also one built using annotations and TeenyApplication](https://github.com/JonathanGiles/TeenyHttpd/blob/master/src/test/java/net/jonathangiles/tools/teenyhttpd/chat/ChatServerButUsingAnnotations.java).\n\n### Message Converters\n\nTeenyApplication provides support for custom message converters. These converters are used to handle specific content types as specified by the user. For example the following code handles requests of content type `application/json`\n\n```java\npublic class GsonMessageConverter implements MessageConverter {\n\n    final Gson gson = new Gson();\n\n    @Override\n    public String getContentType() {\n        return \"application/json\";\n    }\n\n    @Override\n    public void write(Object value, BufferedOutputStream dataOut) throws IOException {\n        if (value instanceof String) {\n            dataOut.write(((String) value).getBytes());\n            return;\n        }\n\n        dataOut.write(gson.toJson(value).getBytes());\n    }\n\n    @Override\n    public Object read(String value, Type type) {\n        if (String.class.isAssignableFrom((Class\u003c?\u003e) type)) {\n            return value;\n        }\n\n        return gson.fromJson(value, type);\n    }\n}\n```\n\nSimilar to Spring, `@Configuration` is used to provide configurations. To specify a custom MessageConverter, you can define your configuration as shown below, within your application:\n\n```java\n@Configuration\npublic GsonMessageConverter getGsonConverter() {\n\treturn new GsonMessageConverter();\n}\n```\n\n## TeenyJson\n\nTeenyHttpd includes a simple JSON library called TeenyJson. It is a simple, lightweight JSON library that is used to convert JSON strings to Java objects, and vice versa.\nIt is not as feature-rich as other JSON libraries, but it is lightweight and easy to use.\n\n### Parsing JSON\n\n```java\nPerson person = new TeenyJson().readValue(json, Person.class);\n```\n\nSimilar to jackson to parse a ambiguous property, you can use the `@JsonDeserialize` annotation:\n\n```java\n@JsonDeserialize(contentAs = ObjectC.class)\npublic void setList(List\u003c? extends ObjectC\u003e list) {\n    this.list = list;\n}\n\n@JsonDeserialize(as = ObjectC.class)\npublic void setC(ObjectC c) {\n    this.c = c;\n}\n```\n\n### Generating JSON\n\n```java\nPerson person = new Person(\"John\", 30, null);\nString json = new TeenyJson().writeValueAsString(person);\n```\n\nTo give a property an alias in the JSON, you can use the `@JsonProperty` annotation:\n\n```java\n@JsonAlias(\"bestSongs\")\npublic Set\u003cString\u003e getFavoriteSongs() {\n    return favoriteSongs;\n}\n```\n\nTo ignore a property in the JSON, you can use the `@JsonIgnore` annotation:\n\n```java\n@JsonIgnore\npublic String getSecret() {\n    return secret;\n}\n```\n\nTo ignore all properties that are null, you can use the `@JsonIncludeNonNull` annotation:\n\n```java\n@JsonIncludeNonNull\npublic class Person {\n// ...\n}\n```\n\nYou can also customize the deserialization and serialization process by specifying a custom serializer or deserializer:\n\n```java\nnew TeenyJson()\n    .registerSerializer(String.class, String::toUpperCase)\n    .registerParser(String.class, (value) -\u003e value.toString().toLowerCase());\n```\n\n## Project Management\n\nReleases are performed using `mvn clean deploy -Prelease`.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonathangiles%2Fteenyhttpd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonathangiles%2Fteenyhttpd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonathangiles%2Fteenyhttpd/lists"}