Code Components
The Registry app is built primarily on the Gin web framework and the go-pg ORM for Postgres.
Additional packages (listed in go.mod) include:
- aws-sdk-go for SES and SNS services (but not for S3 or Glacier)
- go-authy for authy push notifications used in two-factor login
- govalidator for data validation
- httpexpect for testing web and API requests
- nsq for talking to NSQ services
- redis for talking to Redis/Elasticache
- testify for unit and integration tests
- viper for reading config settings
- zerolog for logging
The headings below give a high-level overview of key files and components, describing where to find them, what they do, and how they fit into the system.
This page attempts to give an overview only. Components are described in more detail on dedicated pages.
The Application File
The application file includes essential setup and configuration steps to run the Registry app. This includes:
- Defining routes for the web UI, member API and admin API.
- Defining template helpers, which are functions that can be executed within HTML templates.
- Running code to load all HTML templates at application start.
- Initializing midleware.
The application file defined a single public function called Run() which runs the Registry service. This function is called in registry.go to start the server. It's also called in the test suite to run a background server to handle test queries.
Template Helpers
The templates.go file defines a number of helper functions that can be called from within the application's HTML templates. The functions' names will tell you what they do. Each function also includes a docstring.
Note that these functions must be registered to work inside of templates. The registration happens in the initTeplates()
function in app/application.go
Constants
constant.go defines a number of constants used througout the app. This is to avoid having the app littered with mistyped strings or strings whose cases don't match. The constants' names are descriptive enough to tell you what they mean.
permissions.go defines permissions and which roles they are assigned to. See the Authorization page for details on how permissions are applied.
The Configuration Object
The Configuration Object loads config variables from a .env file and from environment variables, which can be pumped into Docker containers from Amazon's Parameter Store.
In development and test environments, most config settings are stored in .dev.env or .test.env. To load the right config, specify one of the following on the command line:
APT_ENV=dev ./registry serve
or
APT_ENV=test ./registry serve
Config settings are loaded first from the .env file, then from the environment, with environment values overwriting .env file values via viper's AutomaticEnv()
call.
The environment is loaded and made globally available by the Context() function, which returns a singleton instance of APTContext, described below.
The Context Object
The Context() function returns a singleton instance of APTContext, which makes the following items available to all parts of the Registry application:
- A
Configuration
object containing all config settings. - A
DB
object which provides a connection pool to the Postgres database. - A
Log
object for logging. - An
AuthyClient
for two-factor auth push notifications. - A
RedisClient
for talking to Redis. - An
NSQClient
for talking to NSQ. - An
SESClient
for sending emails to users. These are usually password-reset emails, or emails asking someone to review a deletion request. - An
SNSClient
for sending login codes to two-factor auth users via text message.
Security Middleware
Sucurity middleware is registered in the application file. The source is in the middleware directory.
Each piece of middleware touches every request before the registered request handler. The components have the following responsibilities:
Compenent | Responsibility |
---|---|
authenticate.go | Ensures the current user is authenticated before accessing endpoints that require authentication. |
authorize.go | Ensures the user is authorized to perform the current request. This component depends on the authorization_map.go and resource_authorization.go files in the middleware directory, as well as the permissions.go file in the constants directory. |
csrf.go | This ensures that CSRF tokens are present and valid for all POST and PUT requests. |
See the Security Overview for info on how security checks fit into the request lifecycle.
The Request Object
The Request object handles boilerplate processing common to all requests, such as parsing common query data, loading common tempdate data value, showing or hiding submenus, setting up a pager for list responses, and loading requested objects or lists of objects.
There are two versions of the request object: one for web requests and one for API requests.
You'll notice in that in both the Web UI and the REST APIs, most handlers begin with a call to req := NewRequest(c)
to handle the boilerplate setup. (The c
param is the *gin.Context
object, which contains the HTTP request and lots of other metadata.)
The Pager
The pager object contains information about lists, including how many total results a list query yielded and links to the next and previous pages of results. This object works for both Web (HTML) and API (JSON) requests.
Because this object is automatically set up by the Request object, you generally don't have to touch it or think about it.
Custom Forms
The forms directory defines custom forms for each type of object a user or admin may edit through the web UI. It also contains filter forms for all of the Web UI's list pages.
The form objects define what goes into each form. Forms layout and rendering is defined in the views directory. For example, the form for editing user details is in the user form template. while the for for filtering a list of users in in the user filters form.
Views
Views are HTML templates used to render web pages. All of the Registry's views are in the views directory. The application file loads all of them at startup.
Models
The application models are defind in the pgmodels directory. These models map to database tables and views through the go-pg ORM.
Web and API Handlers
All of the handlers for the Web UI are defined in the web/webui directory.
Handlers for the member API, which is a read-only subset of the admin API, are in the web/api/common directory.
Handlers for the admin API are in the web/api/admin directory.
These handlers are mapped to URLs in the application file.
UI Components Page
The UI components page displays available UI components and the HTML required to render them. Refer to this page when creating new features.