{"id":18324050,"url":"https://github.com/dirk/http.jl","last_synced_at":"2025-04-09T15:14:09.702Z","repository":{"id":5566853,"uuid":"6772292","full_name":"dirk/HTTP.jl","owner":"dirk","description":"HTTP library (server, client, parser) for the Julia language","archived":false,"fork":false,"pushed_at":"2014-08-24T18:10:51.000Z","size":455,"stargazers_count":18,"open_issues_count":3,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-09T15:14:04.661Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Julia","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/dirk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-11-20T04:47:58.000Z","updated_at":"2024-02-06T10:20:30.000Z","dependencies_parsed_at":"2022-07-07T03:02:47.178Z","dependency_job_id":null,"html_url":"https://github.com/dirk/HTTP.jl","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/dirk%2FHTTP.jl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dirk%2FHTTP.jl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dirk%2FHTTP.jl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dirk%2FHTTP.jl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dirk","download_url":"https://codeload.github.com/dirk/HTTP.jl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248055275,"owners_count":21040157,"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-05T18:31:22.218Z","updated_at":"2025-04-09T15:14:09.676Z","avatar_url":"https://github.com/dirk.png","language":"Julia","funding_links":[],"categories":[],"sub_categories":[],"readme":"## HTTP.jl\n\nA Julia library defining the specification and providing the data-types for HTTP servers. It also provides a rudimentary **[BasicServer](#using-basicserver)** that can respond to simple HTTP requests. _The spec and the server are in very active development and some breaking changes should be expected along the way._\n\nBesides the spec and server it provides the **[Ocean](#ocean)** library for more easily building your own apps on top of the HTTP.jl spec (ie. Ocean apps can be run on BasicServer with just one line of code).\n\n### Installation\n\n```julia\nPkg.add(\"HTTP\")\n```\n\n### Getting started with HTTP.jl\n\nThe first component of HTTP.jl is the `HTTP` module. This provides the base `Request`, `Response`, and `Cookie` types as well as some basic helper methods for working with those types (however, actually parsing requests into `Requests`s is left to server implementations). Check out [HTTP.jl](src/HTTP.jl) for the actual code; it's quite readable.\n\nHTTP.Util (in [HTTP/Util.jl](src/HTTP/Util.jl)) also provides some helper methods for escaping and unescaping data.\n\n### Using BasicServer\n\nSee the [BasicServer example](examples/basic_server.jl) to get an idea of the function API BasicServer expects (it's a lot like Rack).\n\n### Other notes\n\nThe current spec is heavily inspired by Ruby's [Rack specification](http://rack.rubyforge.org/doc/SPEC.html). The parser parts of the basic server are based off of the WEBrick Ruby HTTP server.\n\n## Ocean\n\n[Ocean](src/Ocean.jl) is a [Sinatra](http://www.sinatrarb.com/)-like library for creating apps that run on the HTTP.jl API (they can currently only be served using BasicServer).\n\n### Hello World\n\nThis will create a basic server on port 8000 that responds with \"Hello World\" to requests at `/`.\n\n```julia\nrequire(\"HTTP/Ocean\")\n\nusing Ocean\n\napp = new_app()\n\nget(app, \"/\", function(req, res, _)\n  return \"Hello World\"\nend)\n\nBasicServer.bind(8000, binding(app), true)\n```\n\nYou can also use Ocean without mucking up your scope with `using`:\n\n```julia\nrequire(\"HTTP/Ocean\")\n\napp = Ocean.app()\n\nOcean.get(app, \"/\", function(req, res, _)\n  return \"Hello World\"\nend)\n\nBasicServer.bind(8000, Ocean.binding(app), true)\n```\n\n### Route parameters\n\nTo capture route parameters format your route as a regular expression with capture groups. For example:\n\n```julia\nOcean.get(app, r\"^/(.+)\", function(req, res, _)\n  return _.params[1]\nend)\n```\n\nA GET request to `/test` would give the response `test`.\n\nIf the route path is a string instead of a regex then `_.params` will be `false`.\n\n#### Parameterized routes\n\nA new (and possibly buggy) feature is parameterized routes. You can create a parameterized route path by calling `Ocean.pr` (or `Ocean.param_route`) or just doing `pr\"/object/:id\"` (this macro-string version is currently only available if you do `using Ocean`). Example:\n\n```julia\n# No-using version\nOcean.get(app, Ocean.pr(\"/:test\"), function(req, res, _)\n  return _.params[\"test\"]\nend)\n# Using version\nget(app, pr\"/:test\", function(req, res, _)\n  return _.params[\"test\"]\nend)\n```\n\n### Request data\n\nLet's say we have the following POST handler:\n\n```julia\nOcean.post(app, \"/\", function(req, res, _)\n  println(req.data)\n  return \"foobar\"\nend)\n```\n\nPOSTing the data `test=testing` would result in something like `{\"test\"=\u003e[\"testing\"]}` being printed to output. Of note is that the value is an array. This is because any key could have multiple values (such as the data `test=testing1\u0026test=testing2`), so for consistency any key in `req.data` will map to an array of values.\n\nOcean provides the shorthand method `gs` (for `get_single`). To get the first value of the key `\"test\"` in the data dictionary you would call `v = gs(req.data, \"test\")` (it will return `false` if the key does not exist). To access this and other utility methods just do `using Ocean.Util` (look at [Ocean/Util.jl](src/Ocean/Util.jl) to see what exactly Ocean.Util provides).\n\n#### Multipart data\n\nPlain multipart data (without a filename and content-type) will be accessible as a regular array of string(s) in the `req.data` dict. Multipart data with a filename and content-type is stored as Multipart objects ([see type definition](src/HTTP.jl#L46)) in the `req.data` dict.\n\n### Redirects\n\nAlso provided by Ocean.Util (`using Ocean.Util`) is the `redirect` method. This will set the `Location` header in the response headers and the response status to 302 (default).\n\n```julia\nusing Ocean.Util\n\nOcean.get(app, ..., function(req, res, _)\n  return redirect(res, \"/\")\n  # To do a 301 redirect:\n  # return redirect(res, \"/\", 301)\nend)\n```\n\nRedirects are also exposed through Ocean.Extra (see _Using templates_ below):\n\n```julia\nOcean.get(app, ..., function(req, res, _)\n  return _.redirect(\"/\")\nend)\n```\n\n### Templates and files\n\nThe third parameter to the request handler (assumed to be `_`) is a Ocean.Extra (type definition [here](src/Ocean.jl#L62)) object that provides some data and functions for common tasks.\n\n#### Reading files\n\nThe `_.file(path::String)` method will return a string of the file's contents or throw an error. If the file starts with `/` then it will open it as an absolute path; if it starts with any other string it will open it relative to the directory of the app file. The contents of files read are cached in `app.cache` with the key `_file:$path`. You can disable caching by making the second parameter `false` (eg. `_.file(path, false)`).\n\n#### Using templates\n\nOcean provides a method in Extra to easily access ejl (embedded Julia) and Mustache template files (for Mustache you must require the Mustache package yourself with `require(\"Mustache\")` or `using Mustache`). It uses the `_.file` method internally to read the path to the file; it also caches the compiled template data in `app.cache` (with the keys `_ejl:$path` and `_mustache:$path`) so that the templates don't have to be recompiled every request.\n\nRendering an ejl template:\n\n```julia\n_.template(:ejl, \"view.ejl\", {\"value\" =\u003e value})\n```\n\nRendering a Mustache template:\n\n```julia\n_.template(:mustache, \"view.mustache\", {\"value\" =\u003e value})\n```\n\n### Getting and setting cookies\n\nThese are basic handlers to get and set cookies:\n\n```julia\nrequire(\"HTTP/Ocean\")\nusing Calendar\nusing Ocean.Util\n\nOcean.get(app, \"/\", function(req, res, _)\n  v = gs(req.cookies, \"test\")\n  if v != false\n    return \"Cookie: \" * v\n  else\n    return \"Cookie not set\"\n  end\nend)\n\n# Expects POST data like \"test=...\" and assigns it to the cookie \"test\".\nOcean.post(app, \"/\", function(req, res, _)\n  postdata = gs(req.data, \"test\")\n  \n  cookie = HTTP.new_cookie(\"test\", postdata, {:expires =\u003e Calendar.now() + Calendar.years(10)})\n  HTTP.set_cookie(res, cookie)\n  \n  return redirect(res, \"/\")\nend)\n```\n\n## Contributing\n\nFork, commit, pull request! Tweet/email me or open an issue if you have any problems or ideas.\n\n## Next steps\n\nOn the drawing board:\n\n* Ocean: Better routing system (\u003cdel\u003eallow for fancy routes like \"/model/:id\"\u003c/del\u003e and such)\n* Ocean: Improve the ejl template system\n* HTTP/BasicServer/Ocean: Improve cookie system\n  * \u003cdel\u003eSplit up cookie system for complete and appropriate separation of concerns\u003c/del\u003e\n  * Improve/clear up cookie system to make it more straightforward and consistent\n* HTTP: \u003cdel\u003eMiddleware API\u003c/del\u003e\n  * HTTP: \u003cdel\u003eSession middleware\u003c/del\u003e\n* BasicServer: \u003cdel\u003eFile/binary upload\u003c/del\u003e\n* Client for performing HTTP requests\n\n## Changelog\n\n### 0.0.3 (WIP)\n#### Improvements\n* Cookie and session middleware\n* Simple (currently blocking) client for performing HTTP requests\n\n### 0.0.2 (2013-03-06)\n#### Improvements\n* Multipart handling\n* New template system\n* Basic middleware system\n* Add Mustache.jl template hooks\n* Add cookie handling\n* Add `file`, `template`, and `redirect` scoped methods to `Extra` objects\n* Add `memo` method to `Util` for easy memoization of data through an associative cache\n* Switch to new evented socket API (and add event-loop-free version of `bind`)\n\n#### Fixes\n* Fix error reporting\n\n### 0.0.1 (2013-02-15)\n#### Improvements\n* Add cookie creation functionality\n* Make `ref` for RegexMatch in `Ocean.Util` work properly\n* Add `Extra` object for route handlers\n\n#### Fixes\n* Make `any` shortcut only create a special `\"ANY\"` route (instead of separate routes for each request method)\n\n### 0.0.0 (2013-02-07)\n* Initial version\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdirk%2Fhttp.jl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdirk%2Fhttp.jl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdirk%2Fhttp.jl/lists"}