{"id":37798133,"url":"https://github.com/mbertschler/guiapi","last_synced_at":"2026-01-16T15:23:02.716Z","repository":{"id":164596713,"uuid":"628419656","full_name":"mbertschler/guiapi","owner":"mbertschler","description":"Guiapi is a multi page web app framework for Go","archived":false,"fork":false,"pushed_at":"2023-09-28T19:38:35.000Z","size":309,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-09-21T14:19:33.463Z","etag":null,"topics":["framework","multi-page-application","router","server-side-rendering"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mbertschler.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":"2023-04-15T22:16:24.000Z","updated_at":"2023-10-06T12:27:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"efc8626b-483e-452b-abbb-24ff8dd589b0","html_url":"https://github.com/mbertschler/guiapi","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/mbertschler/guiapi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mbertschler%2Fguiapi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mbertschler%2Fguiapi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mbertschler%2Fguiapi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mbertschler%2Fguiapi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mbertschler","download_url":"https://codeload.github.com/mbertschler/guiapi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mbertschler%2Fguiapi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28479409,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["framework","multi-page-application","router","server-side-rendering"],"created_at":"2026-01-16T15:22:59.224Z","updated_at":"2026-01-16T15:23:02.699Z","avatar_url":"https://github.com/mbertschler.png","language":"Go","readme":"# `guiapi` - Multi Page Web App Framework for Go\n\n[![Go documentation](https://img.shields.io/badge/Go_documentation-007d9c?logo=go\u0026logoColor=white)](https://pkg.go.dev/github.com/mbertschler/guiapi)\n[![npm package](https://img.shields.io/badge/npm_package-cc0000?logo=npm\u0026logoColor=white)](https://www.npmjs.com/package/guiapi)\n\nGuiapi (an API for GUIs) is a framework for building interactive multi page web\napplications with minimal JavaScript, using Go on the server side for handling\nmost of the logic and rendering the HTML. Besides rendering the different pages,\nit can also update the DOM from the server side, after a server Action was triggered\nby a browser event or JavaScript. It tries to minimize the amount of JavaScript\nthat needs to be written and sent to the browser.\n\n# Principles\n\nGuiapi lives between the worlds of an old school web app, that required a full\npage reload for every user action and a typical modern single page app that\nrequires a REST API and lots of JavaScript to render the different HTML views.\n\nYou should give this framework a try, if you agree with the following principles\nthat guiapi is built on:\n\n- Rendering HTML should not require a REST API\n- Most web apps should be multi page apps out of the box\n- Most of the web apps logic should run on the server side\n- Most HTML should be rendered on the server side\n- JavaScript should only be used for features where it is necessary\n\n### Is this an alternative to React and other frontend frameworks?\n\nThe short answer is no. The goal of guiapi is to provide a framework for a multi\npage server rendered web app, which is a different goal than that of a frontend\nframework. It can make sense to use guiapi and a frontend framework together.\nThe main structure of the different pages and inital page layout can be provided\nvia guiapi pages, and afterwards the frontend framework takes over for user\ninterface components that require a high degree of interactivity. These could be\ncomplex form validations, interactive data visualizations and similar, where server\nroundtrips for every update to the UI would not make sense.\n\nIn practice though, many web apps today are built with a frontend framework which \nrenders 100% of the UI in the browser, even if most of the pages don't need this high\ndegree of interactivy. Instead the pages could just as easily be rendered server side.\nIn those cases it might not even be necessary to use a framework, and the same \nend result can be achieved with just a few lines of vanilla JavaScript for the\ninteractive components.  \n\n# Concepts\n\n![guiapi diagram between server and browser](./doc/guiapi_browser_server_diagram.svg)\n\n### Pages\n\nPages represent the different views of your app. They can be accessed directly by\nnavigating to the page URL, in which case the server returns a usuale HTML document.\nIf you are navigating from one guiapi Page to the next, this can even happen via an\nAction and Update. In this case no full page reload is needed, but the URL and page\ncontent is still updated as if the page was visited directly.\n\n### Actions\n\nActions are events that are sent from the browser to the server. They can either be\noriginating from a HTML element with `ga-on` attribute, or from the guiapi `action()`\nJavaScript function. Actions consist of a name and optional arguments. These\nactions are transferred as JSON via a POST request to the endpoint that is typically\ncalled `/guiapi`. The response to an Action is an Update.\n\n### Updates\n\nUpdates are sent from the server to the browser. They can be the response to an\nAction, or they can be sent via a Stream. Updates consist of a list of HTML updates,\nJS calls and Streams to connect to.\n\n#### HTML updates\nAfter an update is received, the HTML updates are applied to the DOM. This can for\nexample mean that the the element with the selector `#content` should be replaced\nwith some different HTML, or that a new element should be inserted before or after\na spefic selector.\n\n#### JS calls\nJS calls can be explicitly added to an Update, and the function with the given name\nwill be called with the passed arguments. For this to work the function first needs\nto get registered. Besides an explicit JS call it is often useful to run some\nJavaScript in relation to one of the newly added HTML elements. In this case the\nnew HTML needs to have one of the special guiapi attributes like `ga-init`.\n\n### State\n\nSometimes a web page has a certain state that needs to be known to the server too,\nfor example filter settings for a list of items. This state gets transferred with\never Action to the server, and can be updated by receiving a new state in an Update.\nThe state is similar to a cookie and usually doesn't need to be accessed by client\nJavaScript functions.\n\n### Streams\n\nStreams are similar to Actions that return an Update, but instead of returning just\na single Update, the Stream can return many Updates over time, until the Stream is \nclosed. This is not done via a HTTP request, but via a WebSocket connection. Similar\nto actions, a Stream also consists of a name and arguments.\n\n\u003e [!WARNING]  \n\u003e While the other concepts of guiapi (Pages, Actions, Updates) have been proven useful\n\u003e in web applications since 2018, Streams are a new concept for server sent updates and\n\u003e should be considered experimental. They might change significantly in the future.\n\n# API Documentation\n\nThe guiapi API consists of the Go, JavaScript and HTML attribute APIs.\n\n## Go API\n\nSee [Go package documentation](https://pkg.go.dev/github.com/mbertschler/guiapi).\nThe main types to look out for are `Server` which handles HTTP requests, `Page`\nfor page rendering and updating, and `Request` and `Response` that explain the\nRPC format.\n\n### Asset bundling using `esbuild`\n\nThe [assets package](https://pkg.go.dev/github.com/mbertschler/guiapi/assets) contains\na wrapper around [esbuild](https://esbuild.github.io/) that can be used to bundle\nJavaScript and CSS assets.\n\nWith this package you don't need an external JS bundler, as the building can happen\nevery time you start the Go binary to embed your assets. The `esbuild` tool adds about\n5 MB to the binary size, so if you don't need this functionality in production and\ninclude the built assets in another way, for example with `go:embed`, then you can use\nthe `no_esbuild` build tag like this: `go build -tags no_esbuild`, which replaces the\nasset building function with a no-op. You can check if the `esbuild` tool is available\nwith the `assets.EsbuildAvailable()` function.\n\n## HTML attribute API\n\nThe following attributes get activated when `setupGuiapi()` is called after the page\nload, and they also get initialized whenever they appear in HTML that was updated by\nan Update from an Action or Stream.\n\n#### Event handlers: `ga-on`\n\n```html\n\u003cbutton class=\"ga\" ga-on=\"click\" ga-func=\"myClickFunction\"\u003eclick me\u003c/button\u003e\n\u003cbutton class=\"ga\" ga-on=\"click\" ga-action=\"Page.Click\" ga-args=\"abc\"\u003eclick me\u003c/button\u003e\n```\n\nThe `ga-on` attribute is used to trigger a server action or JavaScript functions every time\nthe event name specified in the attribute happens event listeners on HTML elements. In\nthe first example above, the `myClickFunction` function is called every time the button is\nclicked. In the second example, the `Page.Click` server action is called with \"abc\" as the\nargument.\n\n```html\n\u003cinput class=\"my-form\" type=\"text\" name=\"name\" /\u003e\n\u003cinput class=\"my-form\" type=\"number\" name=\"amount\" /\u003e\n\u003cbutton class=\"ga\" ga-on=\"click\" ga-action=\"Page.Click\" ga-values=\".my-form\"\u003esubmit\u003c/button\u003e\n```\n\nIf you want to submit multiple inputs to a server action, you can use the `ga-values`\nattribute. The value of the attribute gets passed to `document.querySelectorAll()` and\nall .... value, name\n\n#### Initializer functions: `ga-init`\n\n```html\n\u003cdiv class=\"ga\" ga-init=\"myInitFunction\" ga-args='{\"val\":123}'\u003e\u003c/div\u003e\n```\n\nIf the `ga-args` can't be parsed as JSON, they are passed as a string to the\nfunction.\n\n#### Lightweight page load: `ga-link`\n\n```html\n\u003ca href=\"/other/page\" class=\"ga\" ga-link\u003eother page\u003c/a\u003e\n```\n\nIf you add `ga-link` attribute to an `a` with a `href`, clicking on the link\nwill navigate to the other page via a guiapi call and partial page update\nwithout reloading the whole page. Behind the scenes the history API is used,\nso that navigating back and forth still works as expected. This is useful if\nyou have some JavaScript logic that should keep running between pages and\nshould also speed up page navigation.\n\n## JavaScript API\n\nTo make a guiapi app work, the `setupGuiapi()` function needs to be called.\nBefore that, any functions that are referenced from HTML or update JSCalls\nneed to be registered with `registerFunctions()`.\n\n#### Calling a server action from JavaScript\n\n```ts\naction(name: string, args: any, callback: (error: any) =\u003e void)\n```\n\nThis can be used to run a server action from any JavaScript. The callback is called\nwith any potential error after the update from the server was applied.\n\n#### Registering your JS functions for guiapi\n\n```ts\nregisterFunctions(obj: { string: Function })\n```\n\nRegisters functions that can be called from HTML via `ga-func` or `ga-init` and\nalso makes them available for JSCalls coming via a server update.\n\n#### Initializing the guiapi app\n\n```ts\nsetupGuiapi(config: {\n  state: any,\n  stream: {\n    name: string,\n    args: any,\n  },\n  debug: boolean,\n  errorHandler: (error: any) =\u003e void,\n})\n```\n\nThis initializes all HTML elements with the `ga` class and sets up the event listeners.\nFunctions that are referenced from the HTML with `ga-func` or `ga-init` need to be\nregistered with `registerFunctions()` before calling `setupGuiapi()`.\n\n#### Debug logging\n\n```ts\ndebugPrinting(enable: boolean)\n```\n\nWith this function you can turn on or off loging whenever guiapi calls an action and\nreceives an update from the server. This can be useful during development.\n\n## Examples\n\nGo to [`./examples`](./examples/) and start the web server with `go run .` to access\nthe 3 examples with your web browser at localhost:8000.\n\nThe 3 examples are:\n\n- `/` contains a guiapi implentation of [TodoMVC](https://todomvc.com/)\n- `/counter` is a simple counter that can be increased and decreased\n- `/reports` is a demonstrates streams by updating the page from the server\n\nThe examples are a good starting point to build your own app with guiapi.\n\n# Contributing\n\nIf you are using guiapi and have any feedback, please let me know.\nIssues and discussions are always welcome.\n\n---\n\nBuilt by [@mbertschler](https://x.com/mbertschler)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmbertschler%2Fguiapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmbertschler%2Fguiapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmbertschler%2Fguiapi/lists"}