{"id":13800543,"url":"https://github.com/nitrogen/simple_bridge","last_synced_at":"2025-04-09T05:11:05.811Z","repository":{"id":570972,"uuid":"202604","full_name":"nitrogen/simple_bridge","owner":"nitrogen","description":"A simple, standardized interface library to Erlang HTTP Servers.","archived":false,"fork":false,"pushed_at":"2024-09-06T19:48:16.000Z","size":3565,"stargazers_count":113,"open_issues_count":16,"forks_count":76,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-02T04:04:07.459Z","etag":null,"topics":["cowboy","erlang","inets","mochiweb","websocket","websockets","yaws"],"latest_commit_sha":null,"homepage":"","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":"Unmaintained","scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nitrogen.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","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":"2009-05-16T14:17:10.000Z","updated_at":"2024-10-23T09:01:12.000Z","dependencies_parsed_at":"2024-10-29T19:25:48.228Z","dependency_job_id":null,"html_url":"https://github.com/nitrogen/simple_bridge","commit_stats":{"total_commits":490,"total_committers":37,"mean_commits":"13.243243243243244","dds":0.5612244897959184,"last_synced_commit":"c806faad5b38b9679f811e75e794f3dc68ff7d40"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitrogen%2Fsimple_bridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitrogen%2Fsimple_bridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitrogen%2Fsimple_bridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitrogen%2Fsimple_bridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nitrogen","download_url":"https://codeload.github.com/nitrogen/simple_bridge/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247980837,"owners_count":21027808,"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":["cowboy","erlang","inets","mochiweb","websocket","websockets","yaws"],"created_at":"2024-08-04T00:01:13.589Z","updated_at":"2025-04-09T05:11:05.796Z","avatar_url":"https://github.com/nitrogen.png","language":"Erlang","readme":"# SimpleBridge\n\n[![Build Status](https://travis-ci.org/nitrogen/simple_bridge.svg?branch=master)](https://travis-ci.org/nitrogen/simple_bridge)\n\nSimpleBridge takes the pain out of coding to multiple Erlang HTTP servers by\ncreating a standardized interface. It currently supports Cowboy, Inets,\nMochiweb, Webmachine, and Yaws.\n\nSimpleBridge is used as the bridge to webservers for two of the most popular\nErlang web frameworks: [Nitrogen Web Framework](http://nitrogenproject.com)\nand [ChicagoBoss](http://chicagoboss.org)\n\nIn a sense, it is similar to [EWGI](http://github.com/skarab/ewgi), except\nSimpleBridge has some key improvements/differences:\n\n  + **Easily extended** - Takes between 200 and 400 lines to add support for a\n    new HTTP server, including the Bridge module itself, as well as default\n    supervisor, and anchor module.\n  + **Websockets** - SimpleBridge provides a single interface for handling\n    websockets. Even servers which don't natively support websockets have a\n    websocket layer with SimpleBridge.  This means **you can run websockets on\n    Inets, Mochiweb, and Webmachine,** none of which natively support\n    Websockets.\n  + **MultiPart File Uploads** - SimpleBridge has better support for HTTP\n    POSTS, including support for multipart file uploads, with size limits and\n    handle-able errors.\n  + **Static File Support** - Support for sending a static file to the browser,\n    using the underlying HTTP server's own methods.\n  + **Cookies Support** - SimpleBridge provides interface functions for getting\n    and setting cookies.\n  + **No Middleware Components** - SimpleBridge does not explicitly support\n    EWGI's concept of \"middleware components\". (Though you could probably fake\n    it, haven't tried.)\n\n  + SimpleBridge is split into three parts:\n    + A Bridge module to allows you to see information about the incoming\n      request and construct a response.\n    + A Default supervisor that starts and configures the underlying server\n      based on either the server-specific configuration, or the univeral Simple\n      Bridge configuration.\n    + A Default **anchor** module, which implements the underlying\n      communication and connection setup for each request, and that interfaces\n      with your appliction through the use of a **handler** module.\n\n## Hello World Example\n\n```erlang\n% SimpleBridge Hello World Example\n\nstart() -\u003e\n  Handler = ?MODULE,\n  simple_bridge:start(mochiweb, Handler).\n\nrun(Bridge) -\u003e\n    HTML = [\n        \"\u003ch1\u003eHello, World!\u003c/h1\u003e\",\n        io_lib:format(\"METHOD: ~p~n\u003cbr\u003e\u003cbr\u003e\", [sbw:request_method(Bridge)]),\n        io_lib:format(\"COOKIES: ~p~n\u003cbr\u003e\u003cbr\u003e\", [sbw:cookies(Bridge)]),\n        io_lib:format(\"HEADERS: ~p~n\u003cbr\u003e\u003cbr\u003e\", [sbw:headers(Bridge)]),\n        io_lib:format(\"QUERY PARAMETERS: ~p~n\u003cbr\u003e\u003cbr\u003e\", [sbw:query_params(Bridge)])\n    ],\n    Bridge2 = sbw:set_status_code(200, Bridge),\n    Bridge3 = sbw:set_header(\"Content-Type\", \"text/html\", Bridge2),\n    Bridge4 = sbw:set_response_data(HTML, Bridge3),\n    sbw:build_response(Bridge4).\n```\n\n## A more complete example:\n\nTo see a complete example handler page using SimpleBridge, demonstrating the\nresults of requests, as well as providing a simple echo websocket server, look at\nthe code of\n[simple_bridge_handler_sample](https://github.com/nitrogen/simple_bridge/blob/ws/src/simple_bridge_handler_sample.erl).\n\n## Quick Start\n\nThere is a built-in quickstart for demoing simple bridge with any backend,\nusing the example mentioned above.\n\nTo try it out:\n\n```bash\ngit clone -b ws git://github.com/nitrogen/simple_bridge.git\ncd simple_bridge\nmake run_inets\n# Feel free to replace \"inets\" with \"cowboy\", \"mochiweb\", \"webmachine\", or \"yaws\"\n```\nThen, open your browser and navigate to http://127.0.0.1:8000\n\n## Starting Simple Bridge\n\nAs demonstrated above, the simplest approach is to just start simple bridge\nwith the appropriate backend (or use the simple_bridge.config). Simple Bridge\nwill then start the server to the specs of your choice.\n\nThe following are all valid ways to start Simple Bridge:\n```erlang\n%% Explicitly start with particular Backend and HandlerMod\nsimple_bridge:start(Backend, HandlerMod).\n\n%% HandlerMod is determined from the handler config variable\nsimple_bridge:start(Backend).  \n\n%% Backend and HandlerMod are both determined by the configuration\nsimple_bridge:start(). \n\n%% Same as simple_bridge:start().\napplication:start(simple_bridge). \n```\n\n**Note**: You will still need to ensure that the dependencies are there for the\nwebserver of your choice.  For example, trying to start Yaws without the yaws\napplication currently in your dependencies will fail.\n\n## The Anchor Module\n\nWhen creating your server using any of the above methods, simple_bridge will\nautomatically use the backend-specific anchor module for the chosen backend\nprovided by Simple Bridge.\n\nThe anchor module serves as an additional layer to eliminate the need to write\n*any* platform-specific code in your application.  The anchor module will\ntransform the platform-specific requests and pass them off to the Handler\nModule in a uniform fashion.\n\n## The Handler Module\n\nA Handler module is a standard module that SimpleBridge will call out to when a\nrequest is made, both standard HTTP requests, and websocket frames.\n\nA Handler module is expected to export the following functions:\n\n  + `run(Bridge)` - Bridge will be an initialized instance of a SimpleBridge\n    object, and the last step of the run will be the return value of\n    `sbw:build_response(Bridge)`\n  + `ws_init(Bridge)` - Called when a websocket connection is initialized.\n    + Return Values:\n      + `ok` - Everything went okay, proceed with the connection.\n      + `{ok, State}` - Everything went okay, proceeed with connection and\n        initialize with the provided `State` (which will be passed to\n        `ws_message`, `ws_info`, and `ws_terminate` functions.\n      + `close` - Everything did not go okay, let's shut down the connection.\n  + `ws_message(Message, Bridge, State)` - Called when a websocket client has\n    sent us something. \n    + `Message` can be:\n      + `{Type, Data}` - `Type` will be either `binary` or `text`, depending on\n      the nature of the message. `Data` will always be a binary. By the nature of the\n      WebSocket protocol, you can be guaranteed that if `Type==text`, that `Data`\n      will be verified to be valid UTF8 Unicode.\n    + Return Values:\n      + `noreply` - No reply will be made.\n      + `{noreply, NewState}` - No reply will be made, but change the state to\n        `NewState`\n      + `{reply, {Type, Data}}` - `Type` can be `text` or `binary` and `Data`\n        can be a binary, list, or iolist.\n      + `{reply, {Type, Data}, NewState}` - Same as `{reply, {Type, Data}}`,\n        except that the internal state will be changed to `NewState`\n      + `{reply, [{Type, Data}]}` - Reply with a list of `{Type, Data}` pairs\n        as a single message broken into several frames.\n      + `{reply, [{Type, Data}], NewState}` - Same as `{reply, [{Type, Data}]}`\n        except change the state to `NewState`\n      + `close` - Kill the connection (will provide the Websocket Error code 1000)\n      + `{close, StatusCode}` - Kill the connection with `StatusCode` (See\n        [RFC6455 Sec 7.4.1](https://tools.ietf.org/html/rfc6455#section-7.4.1)\n        for the list of valid connection codes).\n  + `ws_info(Message, Bridge, State)` - Called when the websocket *process* receives a\n    message (that is, a message was sent from an Erlang process).\n    + `Message` can be any term\n    + Return values are exactly the same as `ws_message`\n  + `ws_terminate(ReasonCode, Bridge, State)` - The websocket is shutting down with\n    `ReasonCode`.\n    + Return Value: `ok`\n\nNotice that each of the call above passes in a `Bridge` object. This object\nwill be how you interface with the underlying server, both retrieving\ninformation about the request (headers, query strings, etc), as well as\nbuilding your response to the server.\n\n### A brief note about `State` and Websockets\n\nIn the above handler functions, `State` can be any term.  It's for your own\napplications to track the state of your application's.  The `State` is local\nonly to the specific client's connection.  For example, it could be used for\nstoring a session identifier (for quick lookup in the session key-value store,\nrather than having to read a cookie from the `Bridge` object), or for tracking\nsome user-specific value that might change from message to message, such as\n\"Away\" or \"Do Not Disturb\" status.  It's provided as a convenience so that you\nwon't need to rely on the process dictionary for tracking this state.  As soon\nas the connection dies, this `State` will cease to exist. It is not, as one\nmight be inclined to believe, an application-wide state.\n\nIf your function returns, for example, the atom `noreply` or the `{reply,\nMessage}` two-tuples, then `State` will remain unchanged.  As such, if you\nsimply don't care about using the `State` variable, then you could easily\nignore the `State` variable by matching it with `_` in your function\ndefinitions, and retuning the \"Stateless\" versions of each return value\n(`noreply`, `{reply, Message}`).\n\n### What can I do with the Bridge?\n\nOnce you have created Bridge object, you can interface with it using a series\nof standardized function calls universal to all bridges.\n\nYou can interface with it using the `sbw` module \"sbw\" is an acronym for\n(S)imple (B)ridge (W)rapper.\n\n**NOTE:** Tuple Module style calls were officially disabled in Erlang 21 and\n*require* you to enable tuple calls as a compile option in your module with:\n\n`-compile(tuple_calls).`\n\nThis option can also be specified in your rebar.config file in the `erl_opts`\nvariable with:\n\n`{erl_opts, [tuple_calls]}.`\n\nSimple Bridge is no longer tested with tuple-module calls as of Simple Bridge\n2.2.0\n\n**Backwards Compatibility Note**: Simple Bridge 1.x required a separate Request\nand Response Object.  This has gone away and now a single Bridge \"object\"\nprovides both the Request and Response interface in a single object. This means\nyou no longer have to track both a request and a response bridge in your\napplication. A single bridge will do, pig.\n\n### Request Bridge Interface\n\n  * **sbw:protocol(Bridge)** - returns request protocol as atom 'http' or 'https'.\n  * **sbw:host(Bridge)** - returns the host value for the request, or the root host from the `x-forwarded-for` header.\n  * **sbw:request_method(Bridge)** - returns atom 'GET', 'POST', 'HEAD', etc.\n  * **sbw:path(Bridge)** - returns the requested path and file (string)\n  * **sbw:peer_ip(Bridge)** - returns the client's IP address in tuple format\n    (74.125.67.100 = `{74, 125, 67, 100}`).\n  * **sbw:peer_port(Bridge)** - returns the client's port (integer)\n  * **sbw:headers(Bridge)**(+) - returns a proplist of headers, `{\u003c\u003c\"header\"\u003e\u003e,\n    \u003c\u003c\"Value1\"\u003e\u003e}, {\u003c\u003c\"header2\"\u003e\u003e, \u003c\u003c\"Value2\"\u003e\u003e}, ...]`.\n  * **sbw:header(Header, Bridge)**(++) - returns the value of a header.\n  * **sbw:cookies(Bridge)**(+) - returns a proplist of cookies,\n    `[{\u003c\u003c\"cookie1\"\u003e\u003e, \u003c\u003c\"Value1\"\u003e\u003e}, {\u003c\u003c\"cookie2\"\u003e\u003e, \u003c\u003c\"Value2\"\u003e\u003e}, ...]`.\n  * **sbw:cookie(Cookie, Bridge)**(++) - returns the value of a cookie.\n  * **sbw:query_params(Bridge)**(+) - returns a proplist of query params,\n    `[{\u003c\u003c\"Query1\"\u003e\u003e, \u003c\u003c\"Value1\"\u003e\u003e}, {\u003c\u003c\"Query2\"\u003e\u003e, \u003c\u003c\"Value2\"\u003e\u003e}, ...]`.\n  * **sbw:query_param(Param, Bridge)**(++) - returns value of a query param\n    named `Param`, `undefined` if not found.\n  * **sbw:query_param_group(Param, Bridge)**(++) - returns values of all query\n    params named `Param` as list, `[\"Value1\", \"Value2\", ...]`,  `[]` if none\n    found.\n  * **sbw:post_params(Bridge)**(+) - returns a proplist of post params,\n    `[{\"Post1\", \"Value1\"}, {\"Post2\", \"Value2\"}, ...]`.\n  * **sbw:post_param(Param, Bridge)**(++) - returns value of a post param named\n    `Param`, `undefined` if not found\n  * **sbw:post_param_group(Param, Bridge)**(++) - returns values of all post\n    params named `Param` as list, `[\"Value1\", \"Value2\", ...]`,  `[]` if none\n    found.\n  * **sbw:param(Param, Bridge)**(++) - returns value of a query or post param\n    named `Param`, `undefined` if not found\n  * **sbw:param_group(Param, Bridge)**(++) - returns values of all query and\n    post params named Param as list, `[\"Value1\", \"Value2\", ...]`,  `[]` if none\n    found.\n  * **sbw:post_files(Bridge)** - returns a list of `#sb_uploaded_file` records,\n    describing the files uploaded in a multipart post. These can be\n    conveniently interfaced with the `sb_uploaded_file` module, documented below\n    in the \"Uploaded File Interface\" section.\n  * **sbw:request_body(Bridge)** - returns the request body that has been read\n    so far as binary.\n  * **sbw:error(Bridge)** - returns an Erlang term describing any errors that\n    happened while parsing a multipart post.\n\n**(+)** Return Values will be a proplist of binaries. Keys are normalized to\nlower-case binaries.\n\n**(++)** Return type will be dependent on the provided Key (`Cookie`, `Header`,\n`Param`, etc).  If the Key is a binary, the return type will be binary. If Key\nis an atom or a string (list), the return type will be a string.\n\n### Uploaded File Interface\n\n`sbw:post_files(Bridge)` returns a list of `#sb_uploaded_file` records, but it's\ninconvenient to have to include the `simple_bridge.hrl` header in your\napplication's modules.  The safer and more portable approach is to use the\n`sb_uploaded_file` module provided by Simple Bridge.\n\nAs with the Bridge module above, all `sb_uploaded_file` objects can be referenced by:\n\n  + `sb_uploaded_file:function_name(File)`\n\n`sb_uploaded_file` exports the following functions:\n\n  * **sb_uploaded_file:original_name(UploadedFile)** - The original name of the file from the\n    user's system\n  * **sb_uploaded_file:temp_file(UploadedFile)** - The temporary name for the file as it's stored\n    on the server. Returns `undefined` if file is kept in memory.\n  * **sb_uploaded_file:size(UploadedFile)** - The size of the file in bytes\n  * **sb_uploaded_file:field_name(UploadedFile)** - The name of the HTML `\u003cinput type=file\u003e`\n    element from the page.\n  * **sb_uploaded_file:data(UploadedFile)** - The entire data of uploaded file. Returns `undefined`\n    if file is stored as temporary file on disk.\n    \n#### Storing uploaded files in RAM rather than on disk\n\nBy default uploaded files are always stored in temporary file\n`sb_uploaded_file:temp_file(UploadedFile)`.  If you want to keep the uploaded\nfiles in memory (`sb_uploaded_file:data(UploadedFile)`) instead of on disk, set\nthe max memory size for uploaded files by setting the `simple_bridge`\nconfiguration variable `{max_file_in_memory_size, SizeinMB}`.  Uploaded files\nlarger than `SizeInMB` are still stored in temporary files.\n\n\n### What can I do with the Response Bridge?\n\nThe response portion of the Bridge object provides you with a standard\ninterface for adding response status codes, headers, cookies, and a body.\n\nEach function below returns a new bridge object, so you will need to \nchain together requests like this:\n\n```erlang\nrun(Bridge) -\u003e\n    Bridge1 = sbw:set_status_code(200, Bridge),\n    Bridge2 = sbw:set_header(\"Header1\", \"Value1\", Bridge1),\n    Bridge3 = sbw:set_response_data(HTML, Bridge2),\n    sbw:build_response(Bridge3).\n```\n    \n### Response Bridge Interface\n\nThe Bridge modules export the following functions:\n\n  * **sbw:set_status_code(Code, Bridge)** - set the HTTP status code. (200, 404, etc.)\n  * **sbw:set_header(Name, Value, Bridge)** - set an HTTP header.\n  * **sbw:clear_headers(Bridge)** - clear all previously set headers.\n  * **sbw:set_cookie(Name, Value, Bridge)** - set a cookie for path \"/\" with\n    expiration in 1 hour.\n  * **sbw:set_cookie(Name, Value, Options, Bridge)** - set a cookie, setting\n    HTTP Options. Options is a proplist looking something supporting the\n    options `domain`, `path`, `max_age`, `secure`, `same_site` and `http_only`.\n    Any or all can be specified like below.\n\n```erlang\n\tOptions = [\n\t   {domain, undefined},\n\t   {path, \"/\"},\n\t   {max_age, 3600}, %% time in seconds\n\t   {secure, false},\n\t   {http_only, false},\n       {same_site, none}  %% can be: none | strict | lax\n\t],\n\tsbw:set_cookie(\"mycookie\", \"mycookievalue\", Options, Bridge).\n```\n  * **sbw:set_cookie(Name, Value, Path, MinutesToLive, Bridge)**\n    *(deprecated)* - set a cookie for the defined `Path` with `MinutesToLive` to\n    define the max age of the cookie. Deprecated in favor of `sbw:set_cookie/4`.\n  * **sbw:clear_cookies(Bridge)** - clear all previously set cookies.\n  * **sbw:set_response_data(Data, Bridge)** - set the data to return in the response. Usually HTML\n    goes here.\n  * **sbw:set_response_file(File, Bridge)** - Send a static file to the browser.\n\n\nFinally, you build the response to send to your HTTP server with the\n`sbw:build_response/1` function.\n\n  * **sbw:build_response(Bridge)** - Create a response tuple that you can hand\n    off to your HTTP server.\n\n**DEPRECATION NOTICE:** For backwards compatibility with SimpleBridge Version\n1, the following functions are also exported. Please refrain from using them in\nfuture code, as they are deprecated.\n\n  * **sbw:status_code/2** - equivilant to `sbw:set_status_code/2`.\n  * **sbw:header/3** - equivilant to `sbw:set_header/3`\n  * **sbw:cookie/3,5** - equivilant to `sbw:set_cookie/3/5`\n  * **sbw:data/2** - equivilant to `sbw:set_response_data/2`\n  * **sbw:file/2** - equivilant to `sbw:set_response_file/2`\n\n## Configuration Options\n\nThe configuration optiosn found in `etc/simple_bridge.config` are all full\ndocumented within the config file itself.  Feel free to copy it to your project\nand use it as a base.\n\n## Migrating from 1.x to 2.x?\n\nSimple Bridge 2.0 should be *mostly* compatible with 1.x versions mostly right\nout of the box, but is only compatible through deprecations.\n\n### Let simple bridge start your server and set up the bridge for you\n\nThe recommended approach to migrating to 2.x is to remove instantiating your\nBridge altogether (that is, remove your `simple_bridge:make_request` and\n`simple_bridge:make_response` functions from your app, and instead rely on the\n\"Handler\" module (above) for handling requests, and the `simple_bridge.config`\nfile for setting up the backend server.\n\nWhen doing this, instead of starting the backend servers yourself in the code,\nyou can rely on Simple Bridge to correctly set up the right configuration based\non `simple_bridge.config` and instantiate the server in the correct way, and\nthen starting your server with Simple Bridge by using something like\n`simple_bridge:start(yaws, my_handler_module)` (or check the \"Starting Simple\nBridge\" section above).\n\n#### You can still set up the bridge yourself, if you prefer\n\nFollowing this paradigm, however, is not a requirement.  If you want to\nmaintain the same basic structure of your app, starting the server yourself,\nhandling the requests yourself, and then simply using Simple Bridge to\ninterface with the requests and response, then the recommended approach would\nbe to convert calls like:\n\n```erlang\nReqBridge = simple_bridge:make_request(cowboy_request_module, Req),\nResBridge = simple_bridge:make_response(cowboy_response_module, Req),\n...\nResBridge:build_response().\n```\n\nto simply using:\n```erlang\nBridge = simple_bridge:make(cowboy, Req),\n...\nsbw:build_response(Bridge).\n```\n\n### Return type changes to look out for in 2.0\n\nOne of the other things to look out for with the move to 2.0 is the handling of\nquery parameter, post parameters, and headers.\n\n* The return value of the `sbw:headers/1`, `sbw:query_params/1`, and\n  `sbw:post_params/1` functions is now a list of proplists of binaries.\n* The return values of the single `sbw:header/query_param/post_param/etc`\n  functions however, will be based on the key provided.  For example, calling\n  `sbw:header(\"x-forwarded-for\", Bridge)` will return a list, while\n  `sbw:header(\u003c\u003c\"x-forwarded-for\"\u003e\u003e, Bridge)` will return a binary.\n\n### Use non-deprecated functions in 2.0\n\nThe last thing to deal with when converting from 1.x to 2.0 is making the\nchanges from the old-style response bridge calls to the new names for the same\nfunctions.  This change was made to disambiguate some of the confusion that\nwould arise from having `sbw:header/2,3,4` and `sbw:cookie/2,3,5` some of which\nbeing setters and some being getters.\n\nSo Make sure that you're using `sbw:set_status_code` instead of\n`Bridge:status_code`, `sbw:set_header` instead of `Bridge:header`, etc.  The\nthing to note, is that **all of the non-deprecated response functions begin\nwith a verb** (e.g. `set_response_data`, `clear_cookies`, `build_response`,\netc). See the \"DEPRECATION NOTICE\" a few sections above.\n\n\n## Questions or Comments\n\nWe can be found on:\n\n  * [The Nitrogen Discord](http://discord.nitrogenproject.com)\n  * [The Erlang Slack](https://erlef.org/slack-invite/erlef) in `#nitrogen`\n  * [The Erlang Forum](https://erlangforums.com/c/erlang-frameworks/nitrogen-forum/66)\n  * [The Nitrogen Mailing List](https://groups.google.com/forum/#!forum/nitrogenweb)\n  * Or you can email Jesse Gumm directly at\n    [gumm@sigma-star.com](mailto:gumm@sigma-star.com)\n\n## Contributing\n\nIf you wish to contribute to SimpleBridge's development, check out our\n[contribution\nguidelines](https://github.com/nitrogen/nitrogen/blob/master/CONTRIB.markdown).\n\n## License and Copyright\n\nSimple Bridge was created by [Rusty Klophaus](http://rusty.io) in 2008 and has\nbeen maintained by [Jesse Gumm](http://jessegumm.com) since 2011.\n\nSimple Bridge is copyright 2008-2023 Rusty Klophaus and Jesse Gumm.\n\nLicensed under the [MIT\nLicense](https://github.com/nitrogen/simple_bridge/blob/master/LICENSE.md)\n","funding_links":[],"categories":["Web Framework Components"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnitrogen%2Fsimple_bridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnitrogen%2Fsimple_bridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnitrogen%2Fsimple_bridge/lists"}