Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
5984393
move old v1 files
JXSnack Aug 13, 2025
f0d38e0
go.mod
JXSnack Aug 13, 2025
4fb4470
very basic server
JXSnack Aug 13, 2025
4650868
add logging example
JXSnack Aug 13, 2025
791fcc3
implement logging
JXSnack Aug 13, 2025
e5531c0
very basic routes
JXSnack Aug 13, 2025
5f339ee
redo routes
JXSnack Oct 31, 2025
1e57530
readme
JXSnack Oct 31, 2025
9131526
session cdocs
JXSnack Oct 31, 2025
b274e92
basic overview for passplate
JXSnack Nov 1, 2025
6bbc97a
basic AST
JXSnack Nov 1, 2025
6f52d88
simple AST nodes
JXSnack Nov 1, 2025
50510df
add NewTextNode
JXSnack Nov 1, 2025
588fcd5
remove old
JXSnack Jan 1, 2026
69f4961
add server configuration
JXSnack Jan 1, 2026
40bff55
config validity
JXSnack Jan 1, 2026
e1f7160
add request logging
JXSnack Jan 1, 2026
c4ee77c
enhance logging by needing less request arguments and fixing colors
JXSnack Jan 6, 2026
bc0ebf8
remove old
JXSnack Jan 6, 2026
303b46f
use NewStandardConfiguration
JXSnack Jan 6, 2026
5d861be
basic request handler
JXSnack Jan 6, 2026
0dcfdf6
add default alert handler
JXSnack Jan 6, 2026
6ef4606
redo old
JXSnack Jan 6, 2026
7d71a0e
better clarification on error handling
JXSnack Jan 6, 2026
97f1533
log when server started
JXSnack Jan 6, 2026
6f9e5c1
basic static and error handling
JXSnack Jan 6, 2026
a6b74b6
add static page example
JXSnack Jan 6, 2026
37f7c2e
dynamic route path generation
JXSnack Jan 6, 2026
89b83c9
basic 404
JXSnack Jan 6, 2026
589276f
actually handle 404 too
JXSnack Jan 6, 2026
a12d0ac
clean id
JXSnack Jan 6, 2026
b2a20aa
add final Route struct
JXSnack Jan 6, 2026
9e6f994
make id always lowercase
JXSnack Jan 6, 2026
64fd9cc
very basic response handling
JXSnack Jan 6, 2026
4970008
add Route to request
JXSnack Jan 6, 2026
17fc292
simple route indexing
JXSnack Jan 6, 2026
7049432
extend Route handler variable
JXSnack Jan 6, 2026
9c95af5
allow for "/" as a URL
JXSnack Jan 6, 2026
4aa0f04
add hello world example
JXSnack Jan 6, 2026
4888fc6
bind routes to paths
JXSnack Jan 6, 2026
42458ed
render routes
JXSnack Jan 6, 2026
53ad385
temporary not found beautifier
JXSnack Jan 7, 2026
cc82939
standardise url splitting
JXSnack Jan 7, 2026
792f8f5
get parameters
JXSnack Jan 7, 2026
c1de9aa
add MustRun˚
JXSnack Jan 7, 2026
bce2143
add Json support
JXSnack Jan 7, 2026
c22d1f0
echo content type
JXSnack Jan 7, 2026
1d5bc31
add support for custom headers
JXSnack Jan 7, 2026
d4e1feb
add download QOL
JXSnack Jan 7, 2026
b53bed2
add file download capabilities
JXSnack Jan 7, 2026
bcda245
add file download example
JXSnack Jan 7, 2026
41c7812
add redirect functionality
JXSnack Jan 7, 2026
31e21ba
add data serving capabilities
JXSnack Jan 7, 2026
c7bad7c
add logs
JXSnack Jan 7, 2026
9e6040e
no double headers
JXSnack Jan 7, 2026
5afcef5
very basic nodes
JXSnack Jan 22, 2026
1b5ceee
indent roots
JXSnack Jan 22, 2026
3f9c6ba
parse from text
JXSnack Jan 22, 2026
dfa3011
Merge remote-tracking branch 'origin/v2' into v2
JXSnack Jan 23, 2026
bfe84ee
give root node a parent
JXSnack Jan 23, 2026
e63ccb4
add text expression
JXSnack Jan 23, 2026
ff61e7c
properly represent if node
JXSnack Jan 23, 2026
7582a2c
fix indentation
JXSnack Jan 23, 2026
3438411
migrate to a state machine
JXSnack Jan 23, 2026
372dbb5
if statement building
JXSnack Jan 23, 2026
c26d526
Expression node now only has one expression
JXSnack Jan 23, 2026
228f486
add error support
JXSnack Jan 23, 2026
8747842
add Kind method to expressions
JXSnack Feb 7, 2026
ad54a7d
remove passplate + add docs
JXSnack Apr 23, 2026
27816af
Merge remote-tracking branch 'origin/v2' into v2
JXSnack Apr 23, 2026
c757abd
add CORS
JXSnack Apr 23, 2026
3452fd3
customizable not found handler
JXSnack Apr 23, 2026
abfdcee
add contributor docs
JXSnack Apr 23, 2026
d767807
make my hours spent writing look less like AI
JXSnack Apr 23, 2026
892b53d
session base
JXSnack Apr 24, 2026
294ea5d
return false if route param not found
JXSnack Apr 24, 2026
0f12ff1
implement cookies
JXSnack Apr 24, 2026
b2b854b
remove redundant TODO
JXSnack Apr 24, 2026
24ec307
implement allowed methods
JXSnack Apr 24, 2026
3a9c30b
session assignment
JXSnack Apr 24, 2026
688fccc
login example
JXSnack Apr 24, 2026
d37f717
add coverage
JXSnack Apr 24, 2026
c546e8f
do not GetSession if the session is destroyed
JXSnack Apr 26, 2026
a2cbec4
implement tick interval for lifetimes
JXSnack Apr 26, 2026
d7b9cdd
delete sessions properly
JXSnack Apr 26, 2026
84709e5
warn bad with bad SameSite cookies
JXSnack Apr 27, 2026
dc250b3
save session LastAccess
JXSnack Apr 27, 2026
3c2a200
expand example
JXSnack Apr 27, 2026
d0ea432
add MustDestroy and load sessions from file
JXSnack Apr 27, 2026
8f130ae
docstring
JXSnack Apr 27, 2026
e0de6d6
rewrite all documentation to enhance clarity and respect all changes
JXSnack Apr 27, 2026
57eb668
user docs
JXSnack Apr 27, 2026
983def1
remove v1
JXSnack Apr 27, 2026
7582204
base
JXSnack Apr 27, 2026
f54243d
mention templating
JXSnack Apr 28, 2026
f478027
basic uploader
JXSnack Apr 28, 2026
4e8ac69
No more code at InternalError
JXSnack Apr 28, 2026
d7f7e58
Remove storage.json
JXSnack Apr 28, 2026
65128e9
Remove storage.json
JXSnack Apr 28, 2026
9f77b88
index page
JXSnack Apr 28, 2026
47e5e25
download files
JXSnack Apr 28, 2026
2e15e82
limit size
JXSnack Apr 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 163 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,164 @@
# Compass
A Poorly Designed Go Web Framework

A Go http wrapper for quick development.

### Features

- Kinda extensible
- Session management
- Resource management
- Questionable caching
- One dependency

Internally, there is also:

- Documentation on how things work and are implemented [/contributor-docs](/contributor-docs)
- ~~Testing suite~~ hmmmmmm

### Why?

There are probably better wrappers out there. Heck, even better Go web server implementations. And
faster, too. This project was started to move from Python (Flask) to Go, but no suitable
replacement was found. Therefore, it was decided to make our own, because reinventing the wheel is
always such a good and well-thought-out decision™

## Documentation

There are docstrings everywhere, and if you want to contribute you should check out our [contributor
documentation](/contributor-docs). Otherwise, here's a quick introduction.

### The basic idea

Every route handler is a function. It gets a `Request` and returns a `Response`. Compass takes
that `Response` and does the actual writing to the client, so you never touch `http.ResponseWriter`.

```go
func handleHello(r compass.Request) compass.Response {
return compass.Text("hello")
}
```

`compass.Text("hello")` builds a response value, and Compass does the rest, just like Flask.

### Getting started

```go
server := compass.NewServer(compass.NewStandardConfiguration())

server.AddRoute("/", func (r compass.Request) compass.Response {
return compass.Text("hello")
})

server.MustRun() // listens on :3000
```

`NewStandardConfiguration()` defaults:

| Option | Default | Note |
|-----------------------|--------------|-------------------------------------------|
| `Port` | `3000` | |
| `AssetDir` | `"assets"` | root for static files |
| `StaticUrl` | `"/static"` | URL prefix for static files |
| `CompassDir` | `".compass"` | where sessions and other state are stored |
| `SessionExpiryTime` | `259200000` | ms; 72 hours |
| `SessionTickInterval` | `300000` | ms; how often we check for session expiry |

You can also dump or load the config struct in JSON, because the configuration has corresponding
field tags.

### Routes

Wrap a segment in `< >` to make it a parameter:

```go
server.AddRoute("/users/<id>", func (r compass.Request) compass.Response {
id, _ := r.GetRouteParam("id")
return compass.Text("user: " + id)
})
```

Routes accept `GET` only by default. Change that on the returned route:

```go
server.AddRoute("/items", handler).AllowedMethods = []string{"get", "post"}
```

### Responses

```go
compass.Text("hello") // 200, just text
compass.TextWithCode("nope", 403) // any status
compass.JsonMarshal(myStruct) // marshals to JSON, 200
compass.Redirect("/login", false) // 303 redirect
compass.DownloadFile("report.pdf", path) // triggers a file download
compass.ServeFile(path, "photo.jpg") // serves picture
```

Headers and cookies go directly on the response value:

```go
resp := compass.JsonMarshal(data)
resp.Headers["X-Request-Id"] = "abc"
resp.SetCookie(compass.Cookie{Name: "theme", Value: "light"})
return resp
```

### Static files

Anything in `assets/static/` is served under `/static/` automatically. Both paths are
configurable.

### Templating

Compass does not come with its own templating engine. We recommend using something like
[fasttemplate](https://github.com/valyala/fasttemplate) and serving its output as text. It is
recommended, but not required, to put your templates in the `assets/templates/` directory. This
is up to you.

### Sessions

Sessions are stored as JSON files in `.compass/session/`, so they survive restarts.

```go
session, err := server.CreateSession()
resp := compass.Redirect("/", false)
resp.SetSession(session)
return resp

// get it back on the next request
session, ok := r.GetSession(server)

// read a value
name, err := compass.SessionGet[string](session, "name")
pfpLink := compass.SessionGetOrDefault[string](session, "profilePicture", "/static/default.png")

// write a value
tx := session.BeginTx()
tx.Set("name", "alice")
tx.Commit()
```

### CORS

```go
return compass.JsonMarshal(data).WithCORS(compass.AllowAll())
```

`AllowAll()` is wide open, which is fine locally, but probably not for production. For production,
set only what you need:

```go
policy := compass.CORSPolicy{Origin: "https://example.com", Methods: []string{"get", "post"}}
return compass.Text("I'm a very secretive text!").WithCORS(policy)
```

### Custom 404 / 405

```go
server.NotFoundHandler = func(r compass.Request) compass.Response {
return compass.TextWithCode("not found", 404)
}
server.MethodNotAllowedHandler = func(r compass.Request) compass.Response {
return compass.TextWithCode("method not allowed", 405)
}
```
185 changes: 0 additions & 185 deletions compass/communication.go

This file was deleted.

Loading