Categorygithub.com/tinkeractive/servotron
modulepackage
0.0.0-20241227152808-b14b5bfe0601
Repository: https://github.com/tinkeractive/servotron.git
Documentation: pkg.go.dev

# README

servotron

Haiku


A deliverance -
an app server for Postgres
without O/R-M.


Why

Although it may seem trite to say it, Object/Relational Mapping is the Vietnam of Computer Science. It represents a quagmire which starts well, gets more complicated as time passes, and before long entraps its users in a commitment that has no clear demarcation point, no clear win conditions, and no clear exit strategy.

https://www.odbms.org/wp-content/uploads/2013/11/031.01-Neward-The-Vietnam-of-Computer-Science-June-2006.pdf

How

  • SQL.
  • Prepared statements provide authorization and API endpoints. PostgreSQL's row level security is also available.
  • Authorization queries must return a boolean value indicating whether the request is authorized for the user.
  • API queries return JSON (via PostgreSQL's JSON functions).
  • User info is set on a per-request basis.
  • For GET and DELETE requests, arguments parsed from the route and query string are passed in the order they appear in the route specification.
  • For POST and PUT requests, the request body JSON is the first argument. The JSON string can be transformed into a record or recordset (for bulk inserts) via PostgreSQL's JSON functions. The data returned from the INSERT and UPDATE queries should contain the fields required of the associated SELECT for the resource.
  • Service routes are proxied to associated service URLs.

Diagram

Alt text

Dependencies

go

Install

git clone
go build
go install

Configuration

{
	"SQLRoot":"example/api",
	"FileServers":{
		"/assets":"example/www",
		"/lib":"example/www"
	},
	"TemplateServers":{
		"/":"example/template"
	},
	"AppUserAuth":{
		"ParseFrom":"Header",
		"Field":"Authorization",
		"Type":"JWT"
	},
	"AppUserLocalParams":{
		"info":"example/api/select/app_user/self.sql",
		"id":"example/api/select/app_user/id.sql"
	},
	"ListenPort":"80"
	"ManagementPort":"9000",
	"DBConnString":"postgresql://servotron@localhost:5432/postgres",
	"DBPoolSize":4,
	"DBNotifyChannels":["public_default"],
	"Debug":true
}

Directories

File paths specified with tilde will resolve to the user home dir.
Can be relative to current dir.
This can cause errors when running with sudo.

App User Auth

Used to extract identifying info for authorization from request.
Value is set in the app_user.auth parameter and available via current_setting function during request.
Can be parsed from Header or Cookie.
If ParseFrom is Header, then specify Field and Type (JWT or String). If Type is JWT, then specify Claim. If Claim is not present, then the entire JWT payload is set.
If ParseFrom is Cookie, then specify Name. If Name is not present, then all cookies are set as a JSON object of key-value pairs.

App User Local Params

Used to set parameters for the duration of the request.
Can also be used for sensible defaults in table definitions.
The result of the specified query is set in the app_user.[key] parameter for the duration of the request.
Value is available via the current_setting function.

File Servers

Static content such as HTML.

Template Servers

Templates written in the go text/template style.
Useful for server side includes.
Useful for altering content based on user roles/permissions.
Server passes the result of app user query to the template.

Management Port

For admin functionality such as route loading.

Pool Size

If not specified, this defaults to the number of CPUs.

Notify Channels

Likely to be removed.
Intended to enqueue messages.
This functionality can be achieved by writing specialized agent listeners.

Debug

If true, server writes error message responses to client.

Route Types

typeHTTPSQL
createPOSTINSERT
readGETSELECT
updatePUTUPDATE
deleteDELETEDELETE
transactionPOSTPUT
service*null

Service route type is proxied to the service URL.

Example

Prerequisites

psql -f example/schema/app/public.sql

Run

servotron --config example/config.cookie.json

Load Routes

curl localhost:9000/routes -d @example/routes.json

Request

curl -b '[email protected]' localhost:8000/api/buckets
[{"bucket_id":1,"name":"bucket_a","active":true}]

curl -b '[email protected]' localhost:8000/api/bucket -XPOST -d '[{"name":"New Bucket"}]'
[{"bucket_id":3,"name":"New Bucket","active":true}]

curl -b '[email protected]' localhost:8000/api/buckets
[{"bucket_id":1,"name":"bucket_a","active":true},
 {"bucket_id":3,"name":"New Bucket","active":true}]

curl -b '[email protected]' localhost:8000/api/bucket/3
{"bucket_id":3,"name":"New Bucket","active":true}

curl -b '[email protected]' localhost:8000/api/bucket -XPUT -d '{"bucket_id":3,"name":"Newish Bucket"}'
[{"bucket_id":3,"name":"Newish Bucket","active":true}]

curl -b '[email protected]' localhost:8000/api/buckets
[{"bucket_id":1,"name":"bucket_a","active":true},
 {"bucket_id":3,"name":"Newish Bucket","active":true}]

curl -b '[email protected]' localhost:8000/api/bucket/3 -XDELETE

curl -b '[email protected]' localhost:8000/api/buckets
[{"bucket_id":1,"name":"bucket_a","active":true}]

curl -b '[email protected]' localhost:8000/api/buckets?active=false
[{"bucket_id":3,"name":"Newish Bucket","active":false}]

# Functions

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
NOTE for server side includes and rendering of static content based on user info NOTE the template handling is not intended to be a full on backend rendering engine NOTE the only template input is a map of user info NOTE depends on AppUserLocalParams["info"] for user details NOTE multiple template dirs and overlays are possible via template config.
No description provided by the author
No description provided by the author
create new router via side effects applied to server and router globals.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
TODO refactor directory handling TODO parse each statement from transaction script TODO or get each statement from the ast TODO execute each statement use SendBatch.

# Variables

globals for simplified access, route reloading.
No description provided by the author
No description provided by the author

# Structs

No description provided by the author
NOTE if route json changes, then the route struct must change.