{"id":13764086,"url":"https://github.com/carbocation/interpose","last_synced_at":"2025-12-17T11:49:08.499Z","repository":{"id":18808132,"uuid":"22022553","full_name":"carbocation/interpose","owner":"carbocation","description":"Minimalist net/http middleware for golang","archived":false,"fork":false,"pushed_at":"2016-12-06T21:52:53.000Z","size":57,"stargazers_count":293,"open_issues_count":1,"forks_count":16,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-08-13T16:06:32.884Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","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/carbocation.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":"2014-07-20T00:19:52.000Z","updated_at":"2025-02-19T18:41:59.000Z","dependencies_parsed_at":"2022-07-28T20:09:59.116Z","dependency_job_id":null,"html_url":"https://github.com/carbocation/interpose","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/carbocation/interpose","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carbocation%2Finterpose","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carbocation%2Finterpose/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carbocation%2Finterpose/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carbocation%2Finterpose/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/carbocation","download_url":"https://codeload.github.com/carbocation/interpose/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carbocation%2Finterpose/sbom","scorecard":{"id":265455,"data":{"date":"2025-08-11","repo":{"name":"github.com/carbocation/interpose","commit":"723534742ba3bbda66268b735aaa41634468acc6"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.3,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":2,"reason":"Found 5/25 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 10 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T11:54:46.733Z","repository_id":18808132,"created_at":"2025-08-17T11:54:46.733Z","updated_at":"2025-08-17T11:54:46.733Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27782839,"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","status":"online","status_checked_at":"2025-12-17T02:00:08.291Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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-08-03T15:01:13.378Z","updated_at":"2025-12-17T11:49:08.481Z","avatar_url":"https://github.com/carbocation.png","language":"Go","readme":"interpose\n=========\n\nInterpose is a minimalist net/http middleware framework for golang. It uses \n`http.Handler` as its core unit of functionality, minimizing complexity\nand maximizing inter-operability with other middleware frameworks.\n\nAll that it does is manage middleware. It comes with nothing baked in. You \nbring your own router, etc. See below for some well-baked examples.\n\nBecause of its reliance on the net/http standard, Interpose is out-of-the-box \ncompatible with the Gorilla framework, goji, nosurf, and many other frameworks and \nstandalone middleware. \n\nMany projects claim to be `http.Handler`-compliant but actually just use `http.Handlers` \nto create a more complicated/less compatible abstraction. Therefore, a goal of the \nproject is also to create adaptors so that non-`http.Handler` compliant middleware can \nstill be used. As an example of this, an adaptor for Negroni middleware is available, \nmeaning that **any middleware that is Negroni compliant is also Interpose compliant**. \nThe same is true for Martini middleware.\n\n## API change\n\nPlease note that the API has recently changed. Previously, the framework applied\nmiddleware in LIFO order. Now it applies middleware in FIFO order.\n\n## Usage\n\nTo use, first:\n\n`go get github.com/carbocation/interpose`\n\n## Basic usage example\n\nHere is one example of using Interpose to execute \nmiddleware that adds the HTTP header \"X-Server-Name\" to every response.\n\nCreate a file `main.go` with the following:\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/carbocation/interpose\"\n)\n\nfunc main() {\n\tmiddle := interpose.New()\n\n\t// Send a header telling the world this is coming from an Interpose Test Server\n\t// You could imagine setting Content-type application/json or other useful\n\t// headers in other circumstances.\n\tmiddle.UseHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {\n\t\trw.Header().Set(\"X-Server-Name\", \"Interpose Test Server\")\n\t}))\n\n\t// In this example, we use a basic router with a catchall route that\n\t// matches any path. In other examples in this project, we use a\n\t// more advanced router.\n\t// The last middleware added is the last executed, so by adding the router\n\t// last, our other middleware get a chance to modify HTTP headers before our\n\t// router writes to the HTTP Body\n\trouter := http.NewServeMux()\n\tmiddle.UseHandler(router)\n\n\trouter.Handle(\"/\", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\tfmt.Fprintf(w, \"Welcome to %s!\", req.URL.Path)\n\t}))\n\n\thttp.ListenAndServe(\":3001\", middle)\n}\n\n```\n\nIn the same path as that file, type `go run main.go`\n\nNow launch your browser and point it to `http://localhost:3001/world` to see output.\n\nAdditional examples can be found below.\n\n## Philosophy\n\nInterpose is a minimalist Golang middleware that uses only `http.Handler` and\n`func(http.Handler)http.Handler`. Interpose takes advantage of closures to create\na stack of native net/http middleware. Unlike other middleware libraries which\ncreate their own net/http-like signatures, interpose uses literal net/http\nsignatures, thus minimizing package lock-in and maximizing inter-compatibility.\n\nMiddleware is called in nested FIFO fashion, which means that the first middleware\nto be added will be the first middleware to be called. Because the middleware is\nnested, it actually means that the first middleware to be added gets the\nopportunity to make the first and the last calls in the stack. For example,\nif there are 3 middlewares added in order (0, 1, 2), the calls look like so:\n\n\t//0 START\n\t\t//1 START\n\t\t\t//2 START\n\t\t\t//2 END\n\t\t//1 END\n\t//0 END\n\n## Middleware\n\nHere is a current list of Interpose compatible middleware that have pre-built \nexamples working with Interpose. Any middleware that yields an `http.Handler` \nor a `func(http.Handler)http.Handler` should be compliant. Pull requests linking \nto other middleware are encouraged.\n\n\n| Middleware | Usage example | Author | Description |\n| -----------|---------------|--------|-------------|\n| [Graceful](https://github.com/stretchr/graceful) | [Graceful example](https://github.com/carbocation/interpose/blob/master/examples/graceful/main.go) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown |\n| [secure](https://github.com/unrolled/secure) | [Secure example](https://github.com/carbocation/interpose/blob/master/examples/secure/main.go) | [Cory Jacobsen](https://github.com/unrolled) | Middleware that implements a few quick security wins |\n| [Gorilla logger](https://github.com/gorilla/handlers) | [Gorilla log example](https://github.com/carbocation/interpose/blob/master/examples/gorillalog/main.go) | [Gorilla team](https://github.com/gorilla/) | Gorilla Apache CombinedLogger |\n| [Logrus](https://github.com/meatballhat/negroni-logrus) | [Logrus example](https://github.com/carbocation/interpose/blob/master/examples/adaptors/logrus/main.go) | [Dan Buch](https://github.com/meatballhat) | Logrus-based logger, also demonstrating how Negroni packages can be used in Interpose |\n| [Buffered output](https://github.com/goods/httpbuf) | [Buffer example](https://github.com/carbocation/interpose/blob/master/examples/buffer/main.go) | [zeebo](https://github.com/zeebo) | Output buffering demonstrating how headers can be written after HTTP body is sent |\n| [nosurf](https://github.com/justinas/nosurf) | [nosurf example](https://github.com/carbocation/interpose/blob/master/examples/nosurf/main.go) | [justinas](https://github.com/justinas) | A CSRF protection middleware for Go. |\n| [BasicAuth](https://github.com/carbocation/interpose/blob/master/middleware/basicAuth.go)| [BasicAuth example](https://github.com/carbocation/interpose/blob/master/examples/basicAuth/main.go)| [Jeremy Saenz](http://github.com/codegangsta) \u0026 [Brendon Murphy](http://github.com/bemurphy) | [HTTP BasicAuth](https://en.wikipedia.org/wiki/Basic_access_authentication) - based on martini's [auth](https://github.com/martini-contrib/auth) middleware|\n| [Martini Auth](https://github.com/martini-contrib/auth) | [Martini Auth example](https://github.com/carbocation/interpose/blob/master/examples/adaptors/martiniauth/main.go) | [Jeremy Saenz](https://github.com/codegangsta) \u0026 [Brendon Murphy](http://github.com/bemurphy) | A basic HTTP Auth implementation that also demonstrates how Martini middleware packages can be used directly in Interpose with a simple wrapper. |\n\n## Adaptors\n\nSome frameworks that are not strictly `http.Handler` compliant use middleware that \ncan be readily converted into Interpose-compliant middleware. So far, adaptors for \nMartini and Negroni have been created. \n\nFor example, to use github.com/urfave/negroni middleware in Interpose, you \ncan use `adaptors.FromNegroni`:\n\n```go\n\tmiddle := interpose.New()\n\n\t// has signature `negroni.Handler`\n\tnegroniMiddleware := negronilogrus.NewMiddleware()\n\n\t// Use the Negroni middleware within Interpose\n\tmiddle.Use(adaptors.FromNegroni(negroniMiddleware))\n\n```\n\n## More examples\n\n### Routing, graceful shutdown, and headers\n\nIn this example, we use the `graceful` package to gracefully release \nconnections after the shutdown signal is encountered. A more powerful \nrouter than in our prior example, Gorilla mux, is used. Also, we send \nthe browser headers indicating that this came from a server named \n\"Interpose Test Server.\"\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/carbocation/interpose\"\n\t\"github.com/gorilla/mux\"\n\t\"github.com/stretchr/graceful\"\n)\n\nfunc main() {\n\tmiddle := interpose.New()\n\n\t// Tell the browser which server this came from.\n\t// This modifies headers, so we want this to be called before\n\t// any middleware which might modify the body (in HTTP, the headers cannot be\n\t// modified after the body is modified)\n\tmiddle.Use(func(next http.Handler) http.Handler {\n\t\treturn http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {\n\t\t\trw.Header().Set(\"X-Server-Name\", \"Interpose Test Server\")\n\t\t\tnext.ServeHTTP(rw, req)\n\t\t})\n\t})\n\n\t// Apply the router. By adding it last, all of our other middleware will be\n\t// executed before the router, allowing us to modify headers before any\n\t// output has been generated.\n\trouter := mux.NewRouter()\n\tmiddle.UseHandler(router)\n\n\trouter.HandleFunc(\"/{user}\", func(w http.ResponseWriter, req *http.Request) {\n\t\tfmt.Fprintf(w, \"Welcome to the home page, %s!\", mux.Vars(req)[\"user\"])\n\t})\n\n\t// Launch and permit graceful shutdown, allowing up to 10 seconds for existing\n\t// connections to end\n\tgraceful.Run(\":3001\", 10*time.Second, middle)\n}\n\n```\n\n### Combined logging and gzipping\n\nPrint an Apache CombinedLog-compatible log statement to StdOut and \ngzip the HTTP response it if the client has gzip capabilities:\n\n```go\npackage main\n\nimport (\n\t\"compress/gzip\"\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/carbocation/interpose\"\n\t\"github.com/carbocation/interpose/middleware\"\n\t\"github.com/gorilla/mux\"\n)\n\nfunc main() {\n\tmiddle := interpose.New()\n\n\t// First apply any middleware that will not write output to http body\n\n\t// Log to stdout. Taken from Gorilla\n\tmiddle.Use(middleware.GorillaLog())\n\n\t// Gzip output that follows. Taken from Negroni\n\tmiddle.Use(middleware.NegroniGzip(gzip.DefaultCompression))\n\n\t// Now apply any middleware that modify the http body.\n\trouter := mux.NewRouter()\n\tmiddle.UseHandler(router)\n\n\trouter.HandleFunc(\"/{user}\", func(w http.ResponseWriter, req *http.Request) {\n\t\tfmt.Fprintf(w, \"Welcome to the home page, %s!\", mux.Vars(req)[\"user\"])\n\t})\n\n\thttp.ListenAndServe(\":3001\", middle)\n}\n\n\n```\n\n### Wrapped middleware\n\nMiddleware can be wrapped around other middleware. In this example, \nwe greet people who arrive at `/{user}`, but we offer a special greeting\nto those who arrive at `/green/{user}`:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/carbocation/interpose\"\n\t\"github.com/carbocation/interpose/middleware\"\n\t\"github.com/gorilla/mux\"\n)\n\nfunc main() {\n\tmiddle := interpose.New()\n\n\t// Invoke the Gorilla framework's combined logger\n\tmiddle.Use(middleware.GorillaLog())\n\n\t// Create a router to serve HTTP content at two paths\n\t// and tell our middleware about the router\n\trouter := mux.NewRouter()\n\tmiddle.UseHandler(router)\n\n\trouter.PathPrefix(\"/green\").Subrouter().Handle(\"/{name}\", Green(http.HandlerFunc(welcomeHandler)))\n\trouter.Handle(\"/{name}\", http.HandlerFunc(welcomeHandler))\n\n\thttp.ListenAndServe(\":3001\", middle)\n}\n\nfunc welcomeHandler(rw http.ResponseWriter, req *http.Request) {\n\tfmt.Fprintf(rw, \"Welcome to the home page, %s\", mux.Vars(req)[\"name\"])\n}\n\nfunc Green(next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {\n\t\trw.Header().Set(\"X-Favorite-Color\", \"green\")\n\t\tnext.ServeHTTP(rw, req)\n\t\tfmt.Fprint(rw, \" who likes green\")\n\t})\n}\n\n```\n\n### Nested middleware: adding headers for only some routes\n\nIn the last example, we applied different middleware to different routes. \nHere we will expand this idea to created fully nested middleware stacks \nwithin different routes. This approach, while more verbose than the last \nexample, is arbitrarily powerful. In this example, routes starting with \n/green are given a special HTTP header X-Favorite-Color: green, \nbut you can also imagine using this same approach to automatically apply \nthe JSON content header for JSON requests, putting authentication in front of\nprotected paths, etc.\n\n```go\npackage main\n\nimport (\n\t\"compress/gzip\"\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/carbocation/interpose\"\n\t\"github.com/carbocation/interpose/middleware\"\n\t\"github.com/gorilla/mux\"\n)\n\nfunc main() {\n\tmiddle := interpose.New()\n\n\t// First call middleware that may manipulate HTTP headers, since\n\t// they must be called before the HTTP body is manipulated\n\n\t// Using Gorilla framework's combined logger\n\tmiddle.Use(middleware.GorillaLog())\n\n\t//Using Negroni's Gzip functionality\n\tmiddle.Use(middleware.NegroniGzip(gzip.DefaultCompression))\n\n\t// Now call middleware that can manipulate the HTTP body\n\n\t// Define the router. Note that we can add the router to our\n\t// middleware stack before we define the routes, if we want.\n\trouter := mux.NewRouter()\n\tmiddle.UseHandler(router)\n\n\t// Configure our router\n\trouter.HandleFunc(\"/{user}\", func(w http.ResponseWriter, req *http.Request) {\n\t\tfmt.Fprintf(w, \"Welcome to the home page, %s!\", mux.Vars(req)[\"user\"])\n\t})\n\n\t// Define middleware that will apply to only some routes\n\tgreenMiddle := interpose.New()\n\n\t// Tell the main router to send /green requests to our subrouter.\n\t// Again, we can do this before defining the full middleware stack.\n\trouter.Methods(\"GET\").PathPrefix(\"/green\").Handler(greenMiddle)\n\n\t// Within the secondary middleware, just like above, we want to call anything that\n\t// will modify the HTTP headers before anything that will modify the body\n\tgreenMiddle.UseHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {\n\t\trw.Header().Set(\"X-Favorite-Color\", \"green\")\n\t}))\n\n\t// Finally, define a sub-router based on our love of the color green\n\t// When you call any url such as http://localhost:3001/green/man , you will\n\t// also see an HTTP header sent called X-Favorite-Color with value \"green\"\n\tgreenRouter := mux.NewRouter().Methods(\"GET\").PathPrefix(\"/green\").Subrouter() //Headers(\"Accept\", \"application/json\")\n\tgreenMiddle.UseHandler(greenRouter)\n\n\tgreenRouter.HandleFunc(\"/{user}\", func(w http.ResponseWriter, req *http.Request) {\n\t\tfmt.Fprintf(w, \"Welcome to the home page, green %s!\", mux.Vars(req)[\"user\"])\n\t})\n\n\thttp.ListenAndServe(\":3001\", middle)\n}\n\n```\n\nFor more examples, please look at the [examples folder](https://github.com/carbocation/interpose/tree/master/examples) \nas well as its subfolder, the [menagerie folder](https://github.com/carbocation/interpose/tree/master/examples/menagerie)\n\n## Authors\nOriginally developed by [carbocation](https://github.com/carbocation). Please see the \n[contributors](https://github.com/carbocation/interpose/blob/master/CONTRIBUTORS.md) \nfile for an expanded list of contributors.\n","funding_links":[],"categories":["Web Frameworks","Libraries for creating HTTP middlewares","Web框架","中间件### 中间件","中间件","XML"],"sub_categories":["Middlewares","创建http中间件的代码库","中间件","Fail injection","中間件"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcarbocation%2Finterpose","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcarbocation%2Finterpose","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcarbocation%2Finterpose/lists"}