{"id":20215155,"url":"https://github.com/root-gg/juliet","last_synced_at":"2025-04-10T14:10:43.853Z","repository":{"id":94144700,"uuid":"48514450","full_name":"root-gg/juliet","owner":"root-gg","description":"Lightweight golang middleware chaining helper with context.","archived":false,"fork":false,"pushed_at":"2016-02-11T16:32:18.000Z","size":14,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-24T12:55:32.306Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/root-gg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-12-23T22:55:34.000Z","updated_at":"2020-03-05T23:52:35.000Z","dependencies_parsed_at":"2023-03-09T07:00:18.421Z","dependency_job_id":null,"html_url":"https://github.com/root-gg/juliet","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/root-gg%2Fjuliet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/root-gg%2Fjuliet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/root-gg%2Fjuliet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/root-gg%2Fjuliet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/root-gg","download_url":"https://codeload.github.com/root-gg/juliet/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248232396,"owners_count":21069487,"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-14T06:20:09.086Z","updated_at":"2025-04-10T14:10:43.829Z","avatar_url":"https://github.com/root-gg.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\nJuliet is a lightweight middleware chaining helper that pass a Context (map) object\nfrom a middleware to the next one.\n\nThis work is inspired by [Stack](https://github.com/alexedwards/stack) by Alex Edwards \nand [Alice](https://github.com/justinas/alice) by Justinas Stankevicius.\n\nGodoc is here : https://godoc.org/github.com/root-gg/juliet   \n\nAnd there is a working example in the examples package :   \n\n```go\npackage main\n\nimport (\n\t\"net/http\"\n\t\"log\"\n\t\"net\"\n\t\"fmt\"\n\n\t\"github.com/root-gg/juliet\"\n)\n\n// Juliet is a lightweight middleware chaining helper that pass a Context (map) object\n// from a middleware to the next one.\n//\n// Middlewre is a pattern where http request/response are passed through many handlers to reuse code.\n\n// For example this classic middleware log the requested url\nfunc logMiddleware(next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t// Our middleware logic goes here...\n\t\tlog.Println(r.URL.String())\n\n\t\t// Pass the request to the next middleware / handler\n\t\tnext.ServeHTTP(w, r)\n\t})\n}\n\n// Juliet adds a context parameter to the middleware pattern that will be passed along the Chain.\n// For example this middleware puts the request's source IP address in the context.\nfunc getSourceIpMiddleware(ctx *juliet.Context, next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\n\t\t// Get the source IP from the request remote address\n\t\tip, _, err := net.SplitHostPort(r.RemoteAddr)\n\n\t\t// You can handle failure at any point of the chain by not calling next.ServeHTTP\n\t\tif err != nil {\n\t\t\thttp.Error(w, \"Unable to parse source ip address\", 500)\n\t\t\treturn\n\t\t}\n\n\t\t// Save the source ip in the context\n\t\tctx.Set(\"ip\", ip)\n\n\t\t// Pass the request to the next middleware / handler\n\t\tnext.ServeHTTP(w, r)\n\t})\n}\n\n// As a context is nothing more that a map[interface{}]interface{} with syntactic sugar you have to ensure you\n// check types of values you get from the context. To keep your code clean you can write helpers to do that and keep\n// type safety everywhere.\nfunc getSourceIp(ctx *juliet.Context) string {\n\tif sourceIP, ok := ctx.Get(\"ip\"); ok {\n\t\treturn sourceIP.(string)\n\t}\n\treturn \"\"\n}\n\n// The last link of a middleware chain is the application Handler\nfunc pingHandler(w http.ResponseWriter, r *http.Request) {\n\tw.Write([]byte(\"pong\\n\"))\n}\n\n// Juliet can also pass the context parameter to application Handlers\nfunc ipHandler(ctx *juliet.Context, resp http.ResponseWriter, req *http.Request) {\n\t// write http response\n\tresp.Write([]byte(fmt.Sprintf(\"your IP address is : %s\\n\", getSourceIp(ctx))))\n}\n\nfunc main(){\n\t// Juliet links middleware and handler with chain objects\n\tchain := juliet.NewChain()\n\n\t// Chain objects are immutable and any operation on it returns a new chain object.\n\t// You can append one or more middleware to the chain at a time using the Append method.\n\tchain = chain.Append(getSourceIpMiddleware)\n\n\t// You can append a middleware to the beginning of the chain with the AppendChain method.\n\t// When working with a non context-aware ( Juliet ) middleware you have to use the Adapt method.\n\tchain = juliet.NewChain(juliet.Adapt(logMiddleware)).AppendChain(chain)\n\n\t// Now we have this middleware chain : logUrl \u003e getSourceIp \u003e ApplicationHandler\n\t// We could have built it in one pass this way :\n\t//  chain := juliet.NewChain(juliet.Adapt(logMiddleware),getSourceIpMiddleware)\n\n\t// It's now time to add some application handlers and to bind everything to some HTTP route.\n\n\t// With a context handler\n\thttp.Handle(\"/ip\", chain.Then(ipHandler))\n\n\t// With a classic http.HandlerFunc\n\thttp.Handle(\"/ping\", chain.ThenHandlerFunc(pingHandler))\n\n\t// With a classic http.Handler\n\thttp.Handle(\"/404\", chain.ThenHandler(http.NotFoundHandler()))\n\n\tlog.Fatal(http.ListenAndServe(\":1234\", nil))\n}\n\n// $ go run main.go\n// 2016/02/01 12:20:39 /ip\n// 2016/02/01 12:20:44 /ping\n// 2016/02/01 12:20:56 /404\n//\n// $ curl 127.0.0.1:1234/ip\n// your IP address is : 127.0.0.1\n// $ curl 127.0.0.1:1234/ping\n// pong\n// $ curl 127.0.0.1:1234/404\n// 404 page not found\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froot-gg%2Fjuliet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Froot-gg%2Fjuliet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froot-gg%2Fjuliet/lists"}