Documentation ¶
Overview ¶
Package jelly is a simple and quick framework dekarrin 'jello' uses for learning Go servers.
"Gelatin-based web servers".
Index ¶
- Constants
- Variables
- func GetURLParam[E any](r *http.Request, key string, parse func(string) (E, error)) (val E, err error)
- func ParseJSONRequest(req *http.Request, v interface{}) error
- func PathParam(nameType string) string
- func RedirectNoTrailingSlash(sp ServiceProvider) http.HandlerFunc
- func RequireIDParam(r *http.Request) uuid.UUID
- func TypedSlice[E any](key string, value interface{}) ([]E, error)
- func UnPathParam(s string) string
- type API
- type APIConfig
- type AuthUser
- type AuthUserRepo
- type AuthUserStore
- type Authenticator
- type Bundle
- func (bndl Bundle) APIBase() string
- func (bndl Bundle) Base() string
- func (bndl Bundle) DB(n int) Store
- func (bndl Bundle) DBNamed(name string) Store
- func (bndl Bundle) Enabled() bool
- func (bndl Bundle) Get(key string) string
- func (bndl Bundle) GetBool(key string) bool
- func (bndl Bundle) GetBoolSlice(key string) []bool
- func (bndl Bundle) GetByteSlice(key string) []byte
- func (bndl Bundle) GetFloat(key string) float64
- func (bndl Bundle) GetFloatSlice(key string) []float64
- func (bndl Bundle) GetInt(key string) int
- func (bndl Bundle) GetInt16(key string) int16
- func (bndl Bundle) GetInt32(key string) int32
- func (bndl Bundle) GetInt64(key string) int64
- func (bndl Bundle) GetInt8(key string) int8
- func (bndl Bundle) GetIntSlice(key string) []int
- func (bndl Bundle) GetSlice(key string) []string
- func (bndl Bundle) GetTime(key string) time.Time
- func (bndl Bundle) GetUint(key string) uint
- func (bndl Bundle) GetUint16(key string) uint16
- func (bndl Bundle) GetUint32(key string) uint32
- func (bndl Bundle) GetUint64(key string) uint64
- func (bndl Bundle) GetUint8(key string) uint8
- func (bndl Bundle) Has(key string) bool
- func (bndl Bundle) Logger() Logger
- func (bndl Bundle) Name() string
- func (bndl Bundle) ServerAddress() string
- func (bndl Bundle) ServerBase() string
- func (bndl Bundle) ServerPort() int
- func (bndl Bundle) UsesDBs() []string
- func (bndl Bundle) WithDBs(dbs map[string]Store) Bundle
- type CommonConfig
- func (cc *CommonConfig) Common() CommonConfig
- func (cc *CommonConfig) FillDefaults() APIConfig
- func (cc *CommonConfig) Get(key string) interface{}
- func (cc *CommonConfig) Keys() []string
- func (cc *CommonConfig) Set(key string, value interface{}) error
- func (cc *CommonConfig) SetFromString(key string, value string) error
- func (cc *CommonConfig) Validate() error
- type Component
- type Config
- type DBType
- type DatabaseConfig
- type EndpointFunc
- type Error
- type ErrorResponse
- type Format
- type Globals
- type LogConfig
- type LogProvider
- type Logger
- type Middleware
- type Override
- type RESTServer
- type ResponseGenerator
- type Result
- type Role
- type ServiceProvider
- type Store
- type UserLoginService
Constants ¶
const ( ConfigKeyAPIName = "name" ConfigKeyAPIBase = "base" ConfigKeyAPIEnabled = "enabled" ConfigKeyAPIUsesDBs = "uses" )
Variables ¶
var ( ErrBadCredentials = errors.New("the supplied username/password combination is incorrect") ErrPermissions = errors.New("you don't have permission to do that") ErrNotFound = errors.New("the requested entity could not be found") ErrAlreadyExists = errors.New("resource with same identifying information already exists") ErrDB = errors.New("an error occured with the DB") ErrBadArgument = errors.New("one or more of the arguments is invalid") ErrBodyUnmarshal = errors.New("malformed data in request") // TODO: merge the two types of errors. ErrDBConstraintViolation = errors.New("a uniqueness constraint was violated") ErrDBNotFound = errors.New("the requested resource was not found") ErrDBDecodingFailure = errors.New("field could not be decoded from DB storage format to model format") )
Functions ¶
func GetURLParam ¶
func ParseJSONRequest ¶
v must be a pointer to a type. Will return error such that errors.Is(err, ErrMalformedBody) returns true if it is problem decoding the JSON itself.
func PathParam ¶
PathParam translates strings of the form "name:type" to a URI path parameter string of the form "{name:regex}" compatible with the routers used in the jelly framework. Only request URIs whose path parameters match their respective regexes (if any) will match that route.
Note that this only does basic matching for path routing. API endpoint logic will still need to decode the received string. Do not rely on, for example, the "email" type preventing malicious or invalid email; it only checks the string.
Currently, PathParam supports the following parameter type names:
- "uuid" - UUID strings.
- "email" - Two strings separated by an @ sign.
- "num" - One or more digits 0-9.
- "alpha" - One or more Latin letters A-Z or a-z.
- "alphanum" - One or more Latin letters A-Z, a-z, or digits 0-9.
If a different regex is needed for a path parameter, give it manually in the path using "{name:regex}" syntax instead of using PathParam; this is simply to use the above listed shortcuts.
If only name is given in the string (with no colon), then the string "{" + name + "}" is returned.
func RedirectNoTrailingSlash ¶
func RedirectNoTrailingSlash(sp ServiceProvider) http.HandlerFunc
RedirectNoTrailingSlash is an http.HandlerFunc that redirects to the same URL as the request but with no trailing slash.
func RequireIDParam ¶
RequireIDParam gets the ID of the main entity being referenced in the URI and returns it. It panics if the key is not there or is not parsable.
func TypedSlice ¶
TypedSlice takes a value that is passed to Set that is expected to be a slice of the given type and performs the required conversions. If a non-nil error is returned it will contain the key name automatically in its error string.
func UnPathParam ¶
Types ¶
type API ¶
type API interface { // Init creates the API initially and does any setup other than routing its // endpoints. It takes in a bundle that allows access to API config object, // connected DBs that the API is configured to use, a logger, and any other // resources available to the initializing API. Only those stores requested // in the API's config in the 'uses' key will be included in the bundle. // // The API should not expect that any other API has yet been initialized, // during a call to Init, and should not attempt to use auth middleware that // relies on other APIs (such as jellyauth's jwt provider). Defer actual // usage to another function, such as Routes. Init(bndl Bundle) error // Authenticators returns any configured authenticators that this API // provides. Other APIs will be able to refer to these authenticators by // name. // // Init must be called before Authenticators is called. It is not gauranteed // that all APIs in the server will have had Init called by the time a given // API has Authenticators called on it. // // Any Authenticator returned from this is automatically registered as an // Authenticator with the Auth middleware engine. Do not do so manually or // there may be conflicts. Authenticators() map[string]Authenticator // Routes returns a router that leads to all accessible routes in the API. // Additionally, returns whether the API's router contains subpaths beyond // just setting methods on its relative root; this affects whether // path-terminal slashes are redirected in the base router the API // router is mounted in. // // An endpoint creator passed in provides access to creation of middleware // configured by the server's main config file for the server to use. // Additionally, it also provides an Endpoint method which will wrap a // jelly-framework style endpoint in an http.HandlerFunc that will apply // standard actions such as logging, error, and panic catching. // // Init is guaranteed to have been called for all APIs in the server before // Routes is called, and it is safe to refer to middleware services that // rely on other APIs within. Routes(ServiceProvider) (router chi.Router, subpaths bool) // TODO: remove subpaths!! // Shutdown terminates any pending operations cleanly and releases any held // resources. It will be called after the server listener socket is shut // down. Implementors should examine the context's Done() channel to see if // they should halt during long-running operations, and do so if requested. Shutdown(ctx context.Context) error }
API holds parameters for endpoints needed to run and a service layer that will perform most of the actual logic. To use API, create one and then assign the result of its HTTP* methods as handlers to a router or some other kind of server mux.
type APIConfig ¶
type APIConfig interface { // Common returns the parts of the API configuration that all APIs are // required to have. Its keys should be considered part of the configuration // held within the APIConfig and any function that accepts keys will accept // the Common keys; additionally, FillDefaults and Validate will both // perform their operations on the Common's keys. // // Performing mutation operations on the Common() returned will not // necessarily affect the APIConfig it came from. Affecting one of its key's // values should be done by calling the appropriate method on the APIConfig // with the key name. Common() CommonConfig // Keys returns a list of strings, each of which is a valid key that this // configuration contains. These keys may be passed to other methods to // access values in this config. // // Each key returned should be alpha-numeric, and snake-case is preferred // (though not required). If a key contains an illegal character for a // particular format of a config source, it will be replaced with an // underscore in that format; e.g. a key called "test!" would be retrieved // from an envvar called "APPNAME_TEST_" as opposed to "APPNAME_TEST!", as // the exclamation mark is not allowed in most environment variable names. // // The returned slice will contain the values returned by Common()'s Keys() // function as well as any other keys provided by the APIConfig. Each item // in the returned slice must be non-empty and unique when all keys are // converted to lowercase. Keys() []string // Get gets the current value of a config key. The parameter key should be a // string that is returned from Keys(). If key is not a string that was // returned from Keys, this function must return nil. // // The key is not case-sensitive. Get(key string) interface{} // Set sets the current value of a config key directly. The value must be of // the correct type; no parsing is done in Set. // // The key is not case-sensitive. Set(key string, value interface{}) error // SetFromString sets the current value of a config key by parsing the given // string for its value. // // The key is not case-sensitive. SetFromString(key string, value string) error // FillDefaults returns a copy of the APIConfig with any unset values set to // default values, if possible. It need not be a brand new copy; it is legal // for implementers to returns the same APIConfig that FillDefaults was // called on. // // Implementors must ensure that the returned APIConfig's Common() returns a // common config that has had its keys set to their defaults as well. FillDefaults() APIConfig // Validate checks all current values of the APIConfig and returns whether // there is any issues with them. // // Implementors must ensure that calling Validate() also calls validation on // the common keys as well as those that they provide. Validate() error }
type AuthUser ¶
type AuthUser struct { ID uuid.UUID // PK, NOT NULL Username string // UNIQUE, NOT NULL Password string // NOT NULL Email string // NOT NULL Role Role // NOT NULL Created time.Time // NOT NULL Modified time.Time // NOT NULL LastLogout time.Time // NOT NULL DEFAULT NOW() LastLogin time.Time // NOT NULL }
AuthUser is an auth model for use in the pre-rolled auth mechanism of user-in-db and login identified via JWT.
type AuthUserRepo ¶
type AuthUserRepo interface { // Create creates a new model in the DB based on the provided one. Some // attributes in the provided one might not be used; for instance, many // Repos will automatically set the ID of new entities on creation, ignoring // any initially set ID. It is up to implementors to decide which attributes // are used. // // This returns the object as it appears in the DB after creation. // // An implementor may provide an empty implementation with a function that // always returns an error regardless of state and input. Consult the // documentation of the implementor for info. Create(context.Context, AuthUser) (AuthUser, error) // Get retrieves the model with the given ID. If no entity with that ID // exists, an error is returned. // // An implementor may provide an empty implementation with a function that // always returns an error regardless of state and input. Consult the // documentation of the implementor for info. Get(context.Context, uuid.UUID) (AuthUser, error) // GetAll retrieves all entities in the associated store. If no entities // exist but no error otherwise occurred, the returned list of entities will // have a length of zero and the returned error will be nil. // // An implementor may provide an empty implementation with a function that // always returns an error regardless of state and input. Consult the // documentation of the implementor for info. GetAll(context.Context) ([]AuthUser, error) // Update updates a particular entity in the store to match the provided // model. Implementors may choose which properties of the provided value are // actually used. // // This returns the object as it appears in the DB after updating. // // An implementor may provide an empty implementation with a function that // always returns an error regardless of state and input. Consult the // documentation of the implementor for info. Update(context.Context, uuid.UUID, AuthUser) (AuthUser, error) // Delete removes the given entity from the store. // // This returns the object as it appeared in the DB immediately before // deletion. // // An implementor may provide an empty implementation with a function that // always returns an error regardless of state and input. Consult the // documentation of the implementor for info. Delete(context.Context, uuid.UUID) (AuthUser, error) // Close performs any clean-up operations required and flushes pending // operations. Not all Repos will actually perform operations, but it should // always be called as part of tear-down operations. Close() error // GetByUsername retrieves the User with the given username. If no entity // with that username exists, an error is returned. GetByUsername(ctx context.Context, username string) (AuthUser, error) }
type AuthUserStore ¶
type AuthUserStore interface { Store // AuthUsers returns a repository that holds users used as part of // authentication and login. AuthUsers() AuthUserRepo }
AuthUserStore is an interface that defines methods for building a DAO store to be used as part of user auth via the jelly framework packages.
TODO: should this be its own "sub-package"? example implementations. Or something. feels like it should live closer to auth-y type things.
type Authenticator ¶
type Authenticator interface { // Authenticate retrieves the user details from the request using whatever // method is correct for the auth handler. Returns the user, whether the // user is currently logged in, and any error that occured. If the user is // not logged in but no error actually occured, a default user and logged-in // = false are returned with a nil error. An error should only be returned // if there is an issue authenticating the user, and a user not being logged // in does not count as an issue. If the user fails to validate due to bad // credentials, that does count and should be returned as an error. // // If the user is logged-in, returns the logged-in user, true, and a nil // error. Authenticate(req *http.Request) (AuthUser, bool, error) // Service returns the UserLoginService that can be used to control active // logins and the list of users. Service() UserLoginService // UnauthDelay is the amount of time that the system should delay responding // to unauthenticated requests to endpoints that require auth. UnauthDelay() time.Duration }
Authenticator is middleware for an endpoint that will accept a request, extract the token used for authentication, and make calls to get a User entity that represents the logged in user from the token.
Keys are added to the request context before the request is passed to the next step in the chain. AuthUser will contain the logged-in user, and AuthLoggedIn will return whether the user is logged in (only applies for optional logins; for non-optional, not being logged in will result in an HTTP error being returned before the request is passed to the next handler).
type Bundle ¶
type Bundle struct {
// contains filtered or unexported fields
}
TODO: combine this bundle with the primary one
func (Bundle) APIBase ¶
APIBase returns the base path of the API that its routes are all mounted at. It will perform any needed normalization of the base string to ensure that it is non-empty, starts with a slash, and does not end with a slash except if it is "/". The returned base path is relative to the ServerBase; combine both ServerBase and APIBase to get the complete URI base path, or call Base() to do it for you.
This is a convenience function equivalent to calling bnd.Get(KeyAPIBase).
func (Bundle) Base ¶
Base returns the complete URIBase path configured for any methods. This takes ServerBase() and APIBase() and appends them together, handling doubled-slashes.
func (Bundle) DB ¶
DB gets the connection to the Nth DB listed in the API's uses. Panics if the API config does not have at least n+1 entries.
func (Bundle) DBNamed ¶
NamedDB gets the exact DB with the given name. This will only return the DB if it was configured as one of the used DBs for the API.
func (Bundle) Enabled ¶
Enabled returns whether the API was set to be enabled. Since this is required for an API to be initialized, this will always be true for an API receiving a Bundle in its Init method.
This is a convenience function equivalent to calling bnd.GetBool(KeyAPIEnabled).
func (Bundle) Get ¶
Get retrieves the value of a string-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetBool ¶
GetBool retrieves the value of a bool-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetBoolSlice ¶
GetBoolSlice retrieves the value of a []bool-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetByteSlice ¶
GetByteSlice retrieves the value of a []byte-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetFloat ¶
GetFloat retrieves the value of a float64-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetFloatSlice ¶
GetFloatSlice retrieves the value of a []float64-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetInt ¶
GetInt retrieves the value of an int-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetInt16 ¶
GetInt16 retrieves the value of an int16-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetInt32 ¶
GetInt32 retrieves the value of an int32-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetInt64 ¶
GetInt64 retrieves the value of an int64-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetInt8 ¶
GetInt8 retrieves the value of an int8-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetIntSlice ¶
GetIntSlice retrieves the value of a []int-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetSlice ¶
GetSlice retrieves the value of a []string-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetTime ¶
GetTime retrieves the value of a time.Time-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetUint ¶
GetUint retrieves the value of a uint-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetUint16 ¶
GetUint16 retrieves the value of a uint16-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetUint32 ¶
GetUint32 retrieves the value of a uint32-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetUint64 ¶
GetUint64 retrieves the value of a uint64-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) GetUint8 ¶
GetUint8 retrieves the value of a uint8-typed API configuration key. If it doesn't exist in the config, the zero-value is returned.
func (Bundle) Name ¶
Name returns the name of the API as read from the API config.
This is a convenience function equivalent to calling bnd.Get(KeyAPIName).
func (Bundle) ServerAddress ¶
ServerAddress returns the address that the server the API is being initialized for will listen on.
func (Bundle) ServerBase ¶
ServerBase returns the base path that all APIs in the server are mounted at. It will perform any needed normalization of the base string to ensure that it is non-empty, starts with a slash, and does not end with a slash except if it is "/". Can be useful for establishing "complete" paths to entities, although if a complete base path to the API is needed, Bundle.Base can be called.
func (Bundle) ServerPort ¶
ServerPort returns the port that the server the API is being initialized for will listen on.
type CommonConfig ¶
type CommonConfig struct { // Name is the name of the API. Must be unique. Name string // Enabled is whether the API is to be enabled. By default, this is false in // all cases. Enabled bool // Base is the base URI that all paths will be rooted at, relative to the // server base path. This can be "/" (or "", which is equivalent) to // indicate that the API is to be based directly at the URIBase of the // server config that this API is a part of. Base string // UsesDBs is a list of names of data stores and authenticators that the API // uses directly. When Init is called, it is passed active connections to // each of the DBs. There must be a corresponding entry for each DB name in // the root DBs listing in the Config this API is a part of. The // Authenticators slice should contain only authenticators that are provided // by other APIs; see their documentation for which they provide. UsesDBs []string }
CommonConfig holds configuration options common to all APIs.
func (*CommonConfig) Common ¶
func (cc *CommonConfig) Common() CommonConfig
func (*CommonConfig) FillDefaults ¶
func (cc *CommonConfig) FillDefaults() APIConfig
FillDefaults returns a new *Common identical to cc but with unset values set to their defaults and values normalized.
func (*CommonConfig) Get ¶
func (cc *CommonConfig) Get(key string) interface{}
func (*CommonConfig) Keys ¶
func (cc *CommonConfig) Keys() []string
func (*CommonConfig) Set ¶
func (cc *CommonConfig) Set(key string, value interface{}) error
func (*CommonConfig) SetFromString ¶
func (cc *CommonConfig) SetFromString(key string, value string) error
func (*CommonConfig) Validate ¶
func (cc *CommonConfig) Validate() error
Validate returns an error if the Config has invalid field values set. Empty and unset values are considered invalid; if defaults are intended to be used, call Validate on the return value of FillDefaults.
type Component ¶
type Component interface { // Name returns the name of the component, which must be unique across all // components that jelly is set up to use. Name() string // API returns a new, uninitialized API that the Component uses as its // server frontend. This instance will be initialized and passed its config // object at config loading time. API() API // Config returns a new APIConfig instance that the Component's config // section is loaded into. Config() APIConfig }
type Config ¶
type Config struct { // Globals is all variables shared with initialization of all APIs. Globals Globals // DBs is the configurations to use for connecting to databases and other // persistence layers. If not provided, it will be set to a configuration // for using an in-memory persistence layer. DBs map[string]DatabaseConfig // APIs is the configuration for each API that will be included in a // configured jelly framework server. Each APIConfig must return a // CommonConfig whose Name is either set to blank or to the key that maps to // it. APIs map[string]APIConfig // Log is used to configure the built-in logging system. It can be left // blank to disable logging entirely. Log LogConfig // Format is the format of config, used in Dump. It will only be // automatically set if the Config was created via a call to Load. Format Format }
Config is a complete configuration for a server. It contains all parameters that can be used to configure its operation.
func (Config) FillDefaults ¶
FillDefaults returns a new Config identical to cfg but with unset values set to their defaults.
type DBType ¶
type DBType string
DBType is the type of a Database connection.
func ParseDBType ¶
ParseDBType parses a string found in a connection string into a DBType.
type DatabaseConfig ¶
type DatabaseConfig struct { // Type is the type of database the config refers to, primarily for data // validation purposes. It also determines which of its other fields are // valid. Type DBType // Connector is the name of the registered connector function that should be // used. The function name must be registered for DBs of the given type. Connector string // DataDir is the path on disk to a directory to use to store data in. This // is only applicable for certain DB types: SQLite, OWDB. DataDir string // DataFile is the name of the DB file to use for an OrbweaverDB (OWDB) // persistence store. By default, it is "db.owv". This is only applicable // for certain DB types: OWDB. DataFile string }
Database contains configuration settings for connecting to a persistence layer.
func ParseDBConnString ¶
func ParseDBConnString(s string) (DatabaseConfig, error)
ParseDBConnString parses a database connection string of the form "engine:params" (or just "engine" if no other params are required) into a valid Database config object.
Supported database types and a sample string containing valid configurations for each are shown below. Placeholder values are between angle brackets, optional parts are between square brackets. Ordering of parameters does not matter.
* In-memory database: "inmem" * SQLite3 DB file: "sqlite:</path/to/db/dir>"" * OrbweaverDB: "owdb:dir=<path/to/db/dir>[,file=<new-db-file-name.owv>]"
func (DatabaseConfig) FillDefaults ¶
func (db DatabaseConfig) FillDefaults() DatabaseConfig
FillDefaults returns a new Database identical to db but with unset values set to their defaults. In this case, if the type is not set, it is changed to types.DatabaseInMemory. If OWDB File is not set, it is changed to "db.owv".
func (DatabaseConfig) Validate ¶
func (db DatabaseConfig) Validate() error
Validate returns an error if the Database does not have the correct fields set. Its type will be checked to ensure that it is a valid type to use and any fields necessary for connecting to that type of DB are also checked.
type EndpointFunc ¶
type Error ¶
type Error struct {
// contains filtered or unexported fields
}
Error is a typed error returned by certain functions in the TunaScript server as their error value. It contains both a message explaining what happened as well as one or more error values it considers to be its causes. Error is compatible with the use of errors.Is() - calling errors.Is on some Error value err along with any value of error it holds as one of its causes will return true. This allows for easy examination and failure condition checking without needing to resort to manual typecasting.
If Error has at least one cause defined, the result of calling Error.Error() will be its primary message with the result of calling Error() on its first cause appended to it.
Error should not be used directly; call New to create one.
func NewError ¶
NewError creates a new Error with the given message, along with any errors it should wrap as its causes. Providing cause errors is not required, but will cause it to return true when it is checked against that error via a call to errors.Is.
func WrapDBError ¶
WrapDBError creates a new Error that wraps the given error as a cause and automatically adds ErrDB as another cause. A user-set message may be provided if desired with msg, but it may be left as "".
The provided error being wrapped will itself be converted to an Error of the approriate jelly type if possible; e.g. SQLite-specific errors indicating that a record could not be found would be converted to an Error that returns true for errors.Is(err, jelly.ErrNotFound).
msg, if provided, is used to create the msg of the error by calling fmt.Sprint. For format capability, use WrapDBErrorf.
func WrapDBErrorf ¶
WrapDBError creates a new Error that wraps the given error as a cause and automatically adds ErrDB as another cause. A user-set message may be provided if desired with format and arguments a.
The provided error being wrapped will itself be converted to an Error of the approriate jelly type if possible; e.g. SQLite-specific errors indicating that a record could not be found would be converted to an Error that returns true for errors.Is(err, jelly.ErrNotFound).
msg, if provided, is used to create the msg of the error by calling fmt.Sprintf.
func (Error) Error ¶
Error returns the message defined for the Error. If a message was defined for it when created, that message is returned, concatenated with the result of calling Error() on the its first cause if one is defined. If no message or an empty message was defined for it when created, but there is at least one cause defined for it, the result of calling Error() on the first cause is returned. If no message is defined and no causes are defined, returns the empty string.
func (Error) Is ¶
Is returns whether Error either Is itself the given target error, or one of its causes is.
This function is for interaction with the errors API.
type ErrorResponse ¶
type Globals ¶
type Globals struct { // Port is the port that the server will listen on. It will default to 8080 // if none is given. Port int // Address is the internet address that the server will listen on. It will // default to "localhost" if none is given. Address string // URIBase is the base path that all APIs are rooted on. It will default to // "/", which is equivalent to being directly on root. URIBase string // The main auth provider to use for the project. Must be the // fully-qualified name of it, e.g. COMPONENT.PROVIDER format. MainAuthProvider string }
Globals are the values of global configuration values from the top level config. These values are shared with every API.
func (Globals) FillDefaults ¶
type LogConfig ¶
type LogConfig struct { // Enabled is whether to enable built-in logging statements. Enabled bool // Provider must be the name of one of the logging providers. If set to // None or unset, it will default to logging.Jellog. Provider LogProvider // File to log to. If not set, all logging will be done to stderr and it // will display all logging statements. If set, the file will receive all // levels of log messages and stderr will show only those of Info level or // higher. File string }
LogConfig contains logging options. Loggers are provided to APIs in the form of sub-components of the primary logger. If logging is enabled, the Jelly server will configure the logger of the chosen provider and use it for messages about the server itself, and will pass a sub-component logger to each API to use for its own logging.
func (LogConfig) FillDefaults ¶
type LogProvider ¶
type LogProvider int
const ( NoLog LogProvider = iota Jellog StdLog )
func ParseLogProvider ¶
func ParseLogProvider(s string) (LogProvider, error)
func (LogProvider) String ¶
func (p LogProvider) String() string
type Logger ¶
type Logger interface { // Debug writes a message to the log at Debug level. Debug(string) // Debugf writes a formatted message to the log at Debug level. Debugf(string, ...interface{}) // Error writes a message to the log at Error level. Error(string) // Errorf writes a formatted message to the log at Error level. Errorf(string, ...interface{}) // Info writes a message to the log at Info level. Info(string) // Infof writes a formatted message to the log at Info level. Infof(string, ...interface{}) // Trace writes a message to the log at Trace level. Trace(string) // Tracef writes a formatted message to the log at Trace level. Tracef(string, ...interface{}) // Warn writes a message to the log at Warn level. Warn(string) // Warnf writes a formatted message to the log at Warn level. Warnf(string, ...interface{}) // DebugBreak adds a 'break' between events in the log at Debug level. The // meaning of a break varies based on the underlying log; for text-based // logs, it is generally a newline character. DebugBreak() // ErrorBreak adds a 'break' between events in the log at Error level. The // meaning of a break varies based on the underlying log; for text-based // logs, it is generally a newline character. ErrorBreak() // InfoBreak adds a 'break' between events in the log at Info level. The // meaning of a break varies based on the underlying log; for text-based // logs, it is generally a newline character. InfoBreak() // TraceBreak adds a 'break' between events in the log at Trace level. The // meaning of a break varies based on the underlying log; for text-based // logs, it is generally a newline character. TraceBreak() // WarnBreak adds a 'break' between events in the log at Warn level. The // meaning of a break varies based on the underlying log; for text-based // logs, it is generally a newline character. WarnBreak() // LogResult logs a request and the response to that request. LogResult(req *http.Request, r Result) }
Logger is an object that is used to log messages. Use the New functions in the logging sub-package to create one.
type Middleware ¶
Middleware is a function that takes a handler and returns a new handler which wraps the given one and provides some additional functionality.
type Override ¶
type Override struct {
Authenticators []string
}
Override is a per-endpoint optional overriding of a global configuration in order to, for instance, use a specific Authenticator. Multiple Overrides can be given in a single Endpoint; if given, they will be evaluated in order with later ones taking precedence over others in cases of conflict and later ones being added to lists at lower prority in cases of lists.
func CombineOverrides ¶
type RESTServer ¶
type ResponseGenerator ¶
type ResponseGenerator interface { OK(respObj interface{}, internalMsg ...interface{}) Result NoContent(internalMsg ...interface{}) Result Created(respObj interface{}, internalMsg ...interface{}) Result Conflict(userMsg string, internalMsg ...interface{}) Result BadRequest(userMsg string, internalMsg ...interface{}) Result MethodNotAllowed(req *http.Request, internalMsg ...interface{}) Result NotFound(internalMsg ...interface{}) Result Forbidden(internalMsg ...interface{}) Result InternalServerError(internalMsg ...interface{}) Result Redirection(uri string) Result Response(status int, respObj interface{}, internalMsg string, v ...interface{}) Result Err(status int, userMsg, internalMsg string, v ...interface{}) Result TextErr(status int, userMsg, internalMsg string, v ...interface{}) Result LogResponse(req *http.Request, r Result) // Logger should not be called by external users of jelly; it is in a // transitory state and is slated for removal in a future release. Logger() Logger }
type Result ¶
type Result struct { Status int IsErr bool IsJSON bool InternalMsg string Resp interface{} Redir string // only used for redirects // contains filtered or unexported fields }
should not be directly init'd probs because log will not be set
func (*Result) PrepareMarshaledResponse ¶
PrepareMarshaledResponse sets the respJSONBytes to the marshaled version of the response if required. If required, and there is a problem marshaling, an error is returned. If not required, nil error is always returned.
If PrepareMarshaledResponse has been successfully called with a non-nil returned error at least once for r, calling this method again has no effect and will return a non-nil error.
func (Result) WithHeader ¶
func (Result) WriteResponse ¶
func (r Result) WriteResponse(w http.ResponseWriter)
type ServiceProvider ¶
type ServiceProvider interface { ResponseGenerator DontPanic() Middleware OptionalAuth(authenticators ...string) Middleware RequiredAuth(authenticators ...string) Middleware SelectAuthenticator(authenticators ...string) Authenticator Endpoint(ep EndpointFunc, overrides ...Override) http.HandlerFunc GetLoggedInUser(req *http.Request) (user AuthUser, loggedIn bool) }
ServiceProvider is passed to an API's Routes method and is used to access jelly middleware and standardized endpoint function wrapping to produce an http.HandlerFunc from an EndpointFunc.
type Store ¶
type Store interface { // Close closes any pending operations on the DAO store and on all of its // Repos. It performs any clean-up operations necessary and should always be // called once the Store is no longer in use. Close() error }
type UserLoginService ¶
type UserLoginService interface { // Login verifies the provided username and password against the existing user // in persistence and returns that user if they match. Returns the user entity // from the persistence layer that the username and password are valid for. // // The returned error, if non-nil, will return true for various calls to // errors.Is depending on what caused the error. If the credentials do not match // a user or if the password is incorrect, it will match ErrBadCredentials. If // the error occured due to an unexpected problem with the DB, it will match // serr.ErrDB. Login(ctx context.Context, username string, password string) (AuthUser, error) // Logout marks the user with the given ID as having logged out, invalidating // any login that may be active. Returns the user entity that was logged out. // // The returned error, if non-nil, will return true for various calls to // errors.Is depending on what caused the error. If the user doesn't exist, it // will match serr.ErrNotFound. If the error occured due to an unexpected // problem with the DB, it will match serr.ErrDB. Logout(ctx context.Context, who uuid.UUID) (AuthUser, error) // GetAllUsers returns all auth users currently in persistence. GetAllUsers(ctx context.Context) ([]AuthUser, error) // GetUser returns the user with the given ID. // // The returned error, if non-nil, will return true for various calls to // errors.Is depending on what caused the error. If no user with that ID exists, // it will match serr.ErrNotFound. If the error occured due to an unexpected // problem with the DB, it will match serr.ErrDB. Finally, if there is an issue // with one of the arguments, it will match serr.ErrBadArgument. GetUser(ctx context.Context, id string) (AuthUser, error) // GetUserByUsername returns the user with the given username. // // The returned error, if non-nil, will return true for various calls to // errors.Is depending on what caused the error. If no user with that ID exists, // it will match serr.ErrNotFound. If the error occured due to an unexpected // problem with the DB, it will match serr.ErrDB. Finally, if there is an issue // with one of the arguments, it will match serr.ErrBadArgument. GetUserByUsername(ctx context.Context, username string) (AuthUser, error) // CreateUser creates a new user with the given username, password, and email // combo. Returns the newly-created user as it exists after creation. // // The returned error, if non-nil, will return true for various calls to // errors.Is depending on what caused the error. If a user with that username is // already present, it will match serr.ErrAlreadyExists. If the error occured // due to an unexpected problem with the DB, it will match serr.ErrDB. Finally, // if one of the arguments is invalid, it will match serr.ErrBadArgument. CreateUser(ctx context.Context, username, password, email string, role Role) (AuthUser, error) // UpdateUser sets all properties except the password of the user with the // given ID to the properties in the provider user. All the given properties // of the user (except password) will overwrite the existing ones. Returns // the updated user. // // This function cannot be used to update the password. Use UpdatePassword for // that. // // The returned error, if non-nil, will return true for various calls to // errors.Is depending on what caused the error. If a user with that username or // ID (if they are changing) is already present, it will match // serr.ErrAlreadyExists. If no user with the given ID exists, it will match // serr.ErrNotFound. If the error occured due to an unexpected problem with the // DB, it will match serr.ErrDB. Finally, if one of the arguments is invalid, it // will match serr.ErrBadArgument. UpdateUser(ctx context.Context, curID, newID, username, email string, role Role) (AuthUser, error) // UpdatePassword sets the password of the user with the given ID to the new // password. The new password cannot be empty. Returns the updated user. // // The returned error, if non-nil, will return true for various calls to // errors.Is depending on what caused the error. If no user with the given ID // exists, it will match serr.ErrNotFound. If the error occured due to an // unexpected problem with the DB, it will match serr.ErrDB. Finally, if one of // the arguments is invalid, it will match serr.ErrBadArgument. UpdatePassword(ctx context.Context, id, password string) (AuthUser, error) // DeleteUser deletes the user with the given ID. It returns the deleted user // just after they were deleted. // // The returned error, if non-nil, will return true for various calls to // errors.Is depending on what caused the error. If no user with that username // exists, it will match serr.ErrNotFound. If the error occured due to an // unexpected problem with the DB, it will match serr.ErrDB. Finally, if there // is an issue with one of the arguments, it will match serr.ErrBadArgument. DeleteUser(ctx context.Context, id string) (AuthUser, error) }
UserLoginService provides a way to control the state of login of users and retrieve users from the backend store.
Directories ¶
Path | Synopsis |
---|---|
Package auth provides user authentication and login services and APIs.
|
Package auth provides user authentication and login services and APIs. |
cmd
|
|
jellytest
Jellytest starts a jelly-based RESTServer that uses the pre-rolled jelly auth API as well as its own separate echo API.
|
Jellytest starts a jelly-based RESTServer that uses the pre-rolled jelly auth API as well as its own separate echo API. |
jellytest/dao
Package dao provides data abstraction objects and database connection functions for the jellytest test server.
|
Package dao provides data abstraction objects and database connection functions for the jellytest test server. |
Package db provides data access objects compatible with the rest of the jelly framework packages.
|
Package db provides data access objects compatible with the rest of the jelly framework packages. |
owdb
Package owdb provides OrbweaverDB stores.
|
Package owdb provides OrbweaverDB stores. |
internal
|
|
config
Package config contains configuration options for the server as well as various config contstants.
|
Package config contains configuration options for the server as well as various config contstants. |
jelsort
Package jelsort provides custom sorting.
|
Package jelsort provides custom sorting. |
middle
Package middle contains middleware for use with the jelly server framework.
|
Package middle contains middleware for use with the jelly server framework. |
tools
|
|
mocks/jelly
Package mock_jelly is a generated GoMock package.
|
Package mock_jelly is a generated GoMock package. |