endpoints

package
v0.59.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 5, 2026 License: Apache-2.0 Imports: 62 Imported by: 0

README

API end-points of DataTug agent

When DataTug agent is started with a serve command it listens on HTTP port (by default 8989).

datatug serve -p=./example

Who is answered

A serve route answers a request only when it comes from one of the server's own pages or from a tool on the same machine, and an answer names a source by its ID. One check stands in front of every route (the routes of the table below, the page at / and the answer to every OPTIONS request; see RequestGuard in request_guard.go):

  • the Host of the request is one that the server was started for: localhost, 127.0.0.1 or ::1, or the host given with --host, on the port that the server listens on;
  • the Origin of the request, when it has one, is on the list of the OPTIONS handler (IsSupportedOrigin: localhost and 127.0.0.1 pages, https://datatug.app and its subdomains, https://app.incidentius.com);
  • the Sec-Fetch-Site of the request, when it has one, is same-origin, same-site or none, or its Origin is on the list.

A request that has neither an Origin nor a Sec-Fetch-Site (the CLI, curl, a script) is answered when its Host passes. Any other request is refused with a 403 whose body is one fixed sentence: it holds nothing the request said, and it names no Access-Control-Allow-Origin. An answer names an origin in Access-Control-Allow-Origin only when it is on the list.

A server that listens on a wildcard address (--host 0.0.0.0) answers Host: 0.0.0.0:<port> and the loopback names, and no other name: the host a client reaches it by has to be given with --host.

The live connection to a database server is a capability that is off by default (see GET /dbserver-databases below): datatug serve --allow-live-connections.

Endpoints

Method Path Description
Executor
POST /exec/execute Executes a batch of commands
GET /exec/select Executes a single non mutating SELECT command
Entities
GET /entities/all_entities
GET /entities/entity
POST /entities/create_entity
PUT /entities/save_entity
DELETE /entities/delete_entity 404 when the project has no such entity; 500 when the delete fails
Projects
POST /projects/create_project 501: not implemented (behind --allow-writes as every write)
Queries
GET /queries/get_query A failure to walk the queries tree of the project is queries of project "<id>" could not be loaded, as for all_queries
GET /queries/all_queries root is shared (the default) or personal; any other value is a 400 that does not quote it
POST /queries/create_query Legacy create-or-replace; needs --allow-writes and a project-write grant for the serving principal
PUT /queries/update_query Legacy create-or-replace; same authorization as create_query
DELETE /queries/delete_query Needs --allow-writes and a project-write grant
POST /queries/capture Save as project query: an atomic, revision-checked create (ifNoneMatch) or update (ifMatch) of a DTQL query pair; same authorization
Recordsets
GET /data/recordsets
GET /data/recordset_definition
GET /data/recordset_data 501: not implemented
POST /data/recordset_add_rows count, when given, is a whole number from 0 to 1000; any other is a 400
PUT /data/recordset_update_rows
DELETE /data/recordset_delete_rows
Folders
PUT /folders/create_folder
DELETE /folders/delete_folder 404 when the project has no such folder; 500 when the delete fails
DB servers
GET /dbserver-summary The db server of the project that the driver, host and port of the query name
GET /dbserver-databases The databases of a SQL Server server (driver=sqlserver) that the served project records. It connects to the server under the identity of the person who runs datatug serve, so it answers 403 unless datatug serve was started with --allow-live-connections. A project that is not served, a server that is not a plain reference and a server that the project does not record are refused with a 400 before anything is connected to; the connection and the query end after 15 seconds, or with the request, with could not list the databases of db server "<id>"
POST /dbserver-add
DELETE /dbserver-delete 404 when the project does not record the server; 500 when the delete fails
Boards
GET /boards/board
POST /boards/create_board
PUT /boards/save_board
DELETE /boards/delete_board 404 when the project has no such board; 500 when the delete fails

The routes of the table above that load a board, an entity, a recordset definition, a folder or a db server, and environment-summary, projects/projects_summary, projects/project_summary, projects/project_full, catalog-tables, queries/all_queries, the semantic routes, the resolution of the source of exec/select, exec/execute_commands and exec/run_query (the connection descriptor of a PostgreSQL catalog included), and the document of a saved query of exec/run_query, answer with a sentence that they build from the kind of what was asked for and its ID (board "b1" not found, could not delete board "b1") when the project store, a driver or a file of the project cannot be read, and read only what the served project records. What the store or the driver said, which quotes the paths of the server, is in the log of the server and is not in the answer.

A source is named by its ID in every answer, for every scheme. Where a route answers that the data file of a source is not there, or that a source could not be opened (the semantic routes, exec/run_query, exec/select and exec/execute_commands), the sentence is built at the route from the ID of the source:

Answer (503, SOURCE_UNAVAILABLE) Built from
the data file of source "<id>" does not exist (run datatug demo to fetch the demo project's data fixtures) the ID
source "<id>" could not be opened the ID

The text of pkg/dbcopy, which holds the display form of the source (the path of its file, the host, the port and the database of a PostgreSQL one), is in the log of the server. The fixed sentences that name no source (the preview of PostgreSQL sources is off, a read through policies is not available, a URL that turns the read-only session off, a connection that was lost) are answered as they are. The CLI's own commands (datatug query run, datatug db copy) show the sentences of pkg/dbcopy: a person at their own terminal sees their own paths.

Endpoint: POST /execute

Executes a batch of commands

Endpoint: GET /select

Executes a single non mutating SELECT command

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidQueriesRoot = errors.New("invalid queries root")

ErrInvalidQueriesRoot is handleError's INVALID_REQUEST trigger (field "root") for an unrecognized ?root= value — the same {code,field} shape api.ErrUnknownStoreID/ErrAmbiguousStore already give ?storage=.

Functions

func AgentInfo

func AgentInfo(w http.ResponseWriter, r *http.Request)

AgentInfo is GET agent-info's exact contract envelope (api-contract.md "Endpoint table"): principal with explicit roles/groups, securityContextId, the projects this process serves, and its capabilities. It replaces the old ad-hoc {version, uptimeMinutes, principal} shape (pkg/api.GetAgentInfo/AgentInfo) — Task 12 item 3.

version reports buildinfo.Get("datatug").Version — see buildInfoFunc. The contract (api-contract.md "Endpoint table", `agent-info` row) defines only `version` on this envelope; commit and build date are deliberately not added here, even though buildinfo.Info carries them, to avoid introducing fields the contract doesn't define.

func IsSupportedOrigin

func IsSupportedOrigin(origin string) bool

IsSupportedOrigin check provided origin is allowed. 127.0.0.1 is accepted interchangeably with localhost (lane C5, datatug-apps PR #59, verified with curl: a dev server or UI addressing the agent via 127.0.0.1 was refused even though the equivalent localhost origin was already allowed).

It is the one list of origins: the OPTIONS handler, the request guard in front of every route and the answers' Access-Control-Allow-Origin all use it. An origin is a scheme, a host and maybe a port, and nothing else (the Origin of a browser never has a path, a query, a fragment or a user), so a text that has more is not on the list whatever it starts or ends with.

func Ping

func Ping(w http.ResponseWriter, _ *http.Request)

Ping return "pong" - is a simplest

func RegisterDatatugHandlers

func RegisterDatatugHandlers(
	pathPrefix string,
	router *httprouter.Router,
	mode RegisterMode,
	wrap wrapper,
	contextProvider func(r *http.Request) (context.Context, error),
	handler Handler,
)

RegisterDatatugHandlers registers datatug HTTP handlers with every write route closed (Capabilities{}) — kept for callers (this package's own tests) that do not need write access. Real `datatug serve` startup uses RegisterDatatugHandlersWithCapabilities.

func RegisterDatatugHandlersWithCapabilities added in v0.20.0

func RegisterDatatugHandlersWithCapabilities(
	pathPrefix string,
	router *httprouter.Router,
	mode RegisterMode,
	wrap wrapper,
	contextProvider func(r *http.Request) (context.Context, error),
	handler Handler,
	caps Capabilities,
)

RegisterDatatugHandlersWithCapabilities is RegisterDatatugHandlers plus an explicit Capabilities gate for this process's mutation routes.

Types

type Capabilities added in v0.20.0

type Capabilities struct {
	AllowWrites bool
	// AllowLiveConnections opens the routes that connect to a database server that the served
	// project records, under the identity of the person who runs the server (today
	// dbserver-databases, which lists the databases of a SQL Server server). It defaults false:
	// without it such a route answers 403 before anything is connected to (see
	// requireLiveConnections, and `datatug serve --allow-live-connections`).
	AllowLiveConnections bool
	// ServedHost and ServedPort are the host and the port that the server listens on. The Host
	// of a request must be a loopback name or address, or ServedHost, on ServedPort (see
	// RequestGuard). A ServedPort of 0 accepts any port.
	ServedHost string
	ServedPort int
}

Capabilities gates whether this process's mutation routes register at all (api-contract.md "Security and errors": "this read journey must not expose an unauthenticated mutation endpoint as a side effect" — REQ:principal-selection: "Unneeded write endpoints MUST fail closed"). AllowWrites defaults false: a `datatug serve` process serving the Phase 1 read journey registers every mutation route behind requireWriteCapability (write_capability.go), which refuses with ACCESS_DENIED before any project file is touched, unless the caller explicitly opted in (see cmd_serve.go's --allow-writes flag).

func (Capabilities) RequestGuard added in v0.57.0

func (c Capabilities) RequestGuard() RequestGuard

RequestGuard is the guard of a server started with these capabilities: the host and port it serves on are the ones of Capabilities.

type ErrorResponse

type ErrorResponse struct {
	Error string `json:"error"`
	Code  string `json:"code,omitempty"`
	Field string `json:"field,omitempty"`
}

ErrorResponse defines format of error response body. Code is set for a structured refusal (currently only "ACCESS_DENIED"); Field is reserved for a future per-field validation error and is not populated yet.

type Handler

type Handler = func(
	w http.ResponseWriter,
	r *http.Request,
	requestDTO apicore.RequestDTO,
	verifyOptions verify.RequestOptions,
	successStatusCode int,
	getContext apicore.ContextProvider,
	handler apicore.Worker,
)

Handler is responsible for creating context and call `handler()` func that should use provided context along with `requestDTO` that was populated from request body Its is exposed publicly so it can be replaced with custom implementation

type ProjectAgentEndpoints

type ProjectAgentEndpoints struct {
}

ProjectAgentEndpoints defines project endpoints

type ProjectEndpoints

type ProjectEndpoints interface {
	CreateProject(w http.ResponseWriter, r *http.Request)
	DeleteProject(w http.ResponseWriter, r *http.Request)
}

ProjectEndpoints defines project endpoints

type RegisterMode

type RegisterMode = int
const (
	RegisterWriteOnlyHandlers RegisterMode = iota
	RegisterAllHandlers
)

type RequestGuard added in v0.57.0

type RequestGuard struct {
	// contains filtered or unexported fields
}

RequestGuard is the one check that stands in front of every route of the server. A route answers a request only when it comes from one of the server's own pages or from a tool on the same machine:

  • its Host is one that the server was started for: a loopback name or address (localhost, 127.0.0.1, ::1) or the host the person configured, with the port the server listens on. A page of another site that makes the browser reach this server by a name of its own (DNS rebinding) carries that name in Host;
  • its Origin, when the request has one, is on the list that the OPTIONS handler uses (IsSupportedOrigin);
  • its Sec-Fetch-Site, when the request has one, is same-origin, same-site or none, or its Origin is on the list. A request that carries neither header (the CLI, curl, a script) is answered when its Host passes.

A refusal is a 403 with a fixed sentence: no echo of what the request said, and no Access-Control-Allow-Origin.

func NewRequestGuard added in v0.57.0

func NewRequestGuard(servedHost string, servedPort int) RequestGuard

NewRequestGuard builds the guard of a server that listens on servedHost and servedPort. The loopback names and addresses are always accepted, whatever servedHost is. A servedPort of 0 says that the port is not known and any port is accepted.

func (RequestGuard) Wrap added in v0.57.0

Wrap returns next behind the guard: the request is refused (see RequestGuard) or answered by next.

type VerifyRequest

type VerifyRequest struct {
	MinContentLength int64
	MaxContentLength int64
	AuthRequired     bool
}

VerifyRequest implements VerifyRequestOptions

func (VerifyRequest) AuthenticationRequired

func (v VerifyRequest) AuthenticationRequired() bool

AuthenticationRequired specifies if authentication is mandatory

func (VerifyRequest) MaximumContentLength

func (v VerifyRequest) MaximumContentLength() int64

MaximumContentLength defines max content length, if < 0 no limit

func (VerifyRequest) MinimumContentLength

func (v VerifyRequest) MinimumContentLength() int64

MinimumContentLength defines min content length

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL