Documentation ¶
Overview ¶
Package rest is scaffolding around net/http that facilitates a RESTful HTTP API with certain patterns implicitly enforced: - When working on the same urls, all Methods should use the exact same data structures. E.g.: What you PUT is the same as what you GET out again. No cheating. - ETag is computed for all responses. - All responses are JSON-encoded, including error messages.
See objects/thing.go for how to use this, but the essence is: 1. Make whatever data structure you need. 2. Implement one or more of gondulapi.Getter/Putter/Poster/Deleter. 3. Use AddHandler() to register that data structure on a URL path 4. Grab lunch.
Receiver tries to do all HTTP and caching-related tasks for you, so you don't have to.
Index ¶
- Variables
- func AddHandler(pathPrefix string, pathPattern string, allocator Allocator) error
- func StartReceiver()
- func UpdateStaticAccessTokens() error
- type AccessTokenEntries
- type AccessTokenEntry
- type Allocator
- type Deleter
- type Getter
- type HTTPError
- type Oauth2InfoData
- type Oauth2LoginData
- type Oauth2LogoutData
- type Poster
- type Putter
- type Request
- type Result
- type Role
- type User
- type Users
Constants ¶
This section is empty.
Variables ¶
var InternalHTTPError = HTTPError{500, "Internal server error"}
InternalHTTPError is provided for the common case of returning an opaque error that can be passed to a user.
Functions ¶
func AddHandler ¶
AddHandler registeres an allocator/data structure with a url. The allocator should be a function returning an empty datastrcuture which implements one or more of gondulapi.Getter, Putter, Poster and Deleter
func StartReceiver ¶
func StartReceiver()
StartReceiver a net/http server and handle all requests registered. Never returns.
func UpdateStaticAccessTokens ¶
func UpdateStaticAccessTokens() error
UpdateStaticAccessTokens deletes the previous static tokens and load new ones from the config. To be called at least when starting the program.
Types ¶
type AccessTokenEntries ¶
type AccessTokenEntries []*AccessTokenEntry
AccessTokenEntries is multiple AccessTokenEntry.
func (*AccessTokenEntries) Get ¶
func (tokens *AccessTokenEntries) Get(request *Request) Result
Get gets multiple access tokens.
type AccessTokenEntry ¶
type AccessTokenEntry struct { ID uuid.UUID `column:"id" json:"id"` Key string `column:"key" json:"key,omitempty"` // TODO rename to just "user" since the DB is fixed now OwnerUserID *uuid.UUID `column:"owner_user" json:"owner_user,omitempty"` // Optional, not used for e.g. test status scripts. NonUserRole *Role `column:"non_user_role" json:"non_user_role,omitempty"` // Role if not a user token. Call .GetRole() to get the effective role. CreationTime time.Time `column:"creation_time" json:"creation_time"` ExpirationTime time.Time `column:"expiration_time" json:"expiration_time"` IsStatic bool `column:"static" json:"static"` // If the token is static, i.e. defined by the config instead of DB and can't be created or deleted through the API. Comment string `column:"comment" json:"comment"` OwnerUser *User `column:"-" json:"-"` // The linked user (if any). Do not modify this object. Call .LoadUser() again if the underlying user is modified. }
AccessTokenEntry is a collections of access things used for the client to authenticate itself and for the backend to know more about the client.
func (*AccessTokenEntry) Get ¶
func (token *AccessTokenEntry) Get(request *Request) Result
Get gets a single access token.
func (*AccessTokenEntry) GetRole ¶
func (token *AccessTokenEntry) GetRole() Role
GetRole returns the non-user role if non-user token or the user role if user token. Assumes the user is already loaded if user token. Returns an empty string (the invalid role) if inconsistent token.
func (*AccessTokenEntry) IsAuthenticated ¶
func (token *AccessTokenEntry) IsAuthenticated() bool
IsAuthenticated checks if the requestor is authenticated.
type Allocator ¶
type Allocator func() interface{}
Allocator is used to allocate a data structure that implements at least one of Getter, Putter, Poster or Deleter from gondulapi.
type Deleter ¶
Deleter should delete the object identified by the element. It should be idempotent, in that it should be safe to call it on already-deleted items.
type Getter ¶
Getter implements Get method, which should fetch the object represented by the element path.
type HTTPError ¶
type HTTPError struct { Code int `json:"-"` Message interface{} }
HTTPError is used to combine a text-based error with a HTTP error code.
func HTTPErrorf ¶
HTTPErrorf is a convenience-function to provide an Error data structure, which is essentially the same as fmt.Errorf(), but with an HTTP status code embedded into it which can be extracted.
func HTTPErrori ¶
HTTPErrori creates an error with the given status-code, with i as the message. i should either be a text string or implement fmt.Stringer
type Oauth2InfoData ¶
type Oauth2InfoData struct { ClientID string `json:"client_id"` AuthURL string `json:"auth_url"` RedirectURL string `json:"redirect_url"` }
Oauth2InfoData is the object for OAuth2 info requests.
func (*Oauth2InfoData) Get ¶
func (response *Oauth2InfoData) Get(request *Request) Result
Get gets OAuth2 info.
type Oauth2LoginData ¶
type Oauth2LoginData struct { User User `json:"user"` Token AccessTokenEntry `json:"token"` }
Oauth2LoginData is the object for OAuth2 login requests.
func (*Oauth2LoginData) Post ¶
func (response *Oauth2LoginData) Post(request *Request) Result
Post attempts to login using OAuth2.
type Oauth2LogoutData ¶
type Oauth2LogoutData struct{}
Oauth2LogoutData is the object for OAuth2 login requests.
func (*Oauth2LogoutData) Post ¶
func (response *Oauth2LogoutData) Post(request *Request) Result
Post deletes the current access token. Supports user tokens only.
type Poster ¶
Poster is not necessarily idempotent, but can be. It should write the object provided, potentially generating a new ID for it if one isn't provided in the data structure itself. Post should ignore the request element.
type Putter ¶
Putter is an idempotent method that requires an absolute path. It should (over-)write the object found at the element path.
type Request ¶
type Request struct { ID uuid.UUID Method string AccessToken AccessTokenEntry PathArgs map[string]string QueryArgs map[string]string ListLimit int // How many elements to return in listings (convenience) ListBrief bool // If only the most relevant fields should be included listings (convenience) }
Request contains the last part of the URL (without the handler prefix), certain query args, and a limit on how many elements to get.
type Result ¶
type Result struct { Message string `json:"message,omitempty"` // Message for client Code int `json:"-"` // HTTP status Location string `json:"-"` // For location header if code 3xx Error error `json:"-"` // Internal error, forces code 500, hidden from client to avoid leak }
Result is an update report on write-requests. The precise meaning might vary, but the gist should be the same.
func UnauthorizedResult ¶
func UnauthorizedResult(token AccessTokenEntry) Result
UnauthorizedResult returns a 401 if the token is not authenticated or 403 if it is.
type Role ¶
type Role string
Role defines a role for users and tokens.
const ( // RoleInvalid - Invalid. RoleInvalid Role = "" // RoleGuest - No special access, for non-authenticated requests. RoleGuest Role = "guest" // RoleParticipant - Access to participate (i.e. logged in). Valid for user tokens only. RoleParticipant Role = "participant" // RoleOperator - Access to most stuff, but can't create new tracks, push status, etc. RoleOperator Role = "operator" // RoleAdmin - Access to everything. RoleAdmin Role = "admin" // RoleTester - Access to push test data, for status scripts. Valid for non-user tokens only. RoleTester Role = "tester" // RoleRunner - Access to modify stations, e.g. for updating the status when reprovisioning them. Valid for non-user tokens only. RoleRunner Role = "runner" )
type User ¶
type User struct { ID *uuid.UUID `column:"id" json:"id"` // Required, unique Username string `column:"username" json:"username"` // Required, unique DisplayName string `column:"display_name" json:"display_name"` // Required EmailAddress string `column:"email_address" json:"email_address"` // Required Role Role `column:"role" json:"role"` // Required (valid) }
User reperesent a single user, including registry information. This is retrieved from the frontend, so where it comes from is somewhat irrelevant.
func (*User) ExistsWithID ¶
ExistsWithID checks whether a user with the specified ID exists or not.
func (*User) ExistsWithUsername ¶
ExistsWithUsername checks whether a user with the specified username exists or not.