When someone signs up for an Info Session on operationspark.org, this service runs a series of tasks:
- Sends a webhook to Greenlight
- Sends a Slack message to the #signups channel.
- Sends the user a confirmation email
- Registers the user for the Info Session's Zoom meeting
Google provides a framework to run the serverless functions locally. The framework starts an HTTP server that wraps the serverless function(s). You can start the local server with the terminal or VS Code
$ cd cmd
$ SLACK_WEBHOOK_URL=[webhook endpoint] go run main.go
Serving function:
Then trigger the function with an HTTP request (cURL, Postman, etc)
$ curl --header "Content-Type: application/json" \
--request POST \
--data '{"firstName":"Quinta", "lastName": "Brunson"}' \
http://localhost:8080/
Use the "Local Function Server" debug configuration:
There is a signupService
struct that has a list of tasks
to run on a signup form event from the operationspark.org website.
A task
is an interface with run
and name
methods.
type task interface {
// Run takes a signup form struct and executes some action.
// Ex.: Send an email, post a Slack message.
run(context.Context, Signup) error
// Name Returns the name of the task.
name() string
}
When someone signs up for an Info Session, the form is parsed, then passed to a series of tasks for processing.
// function.go
// Set up services/tasks to run when someone signs up for an Info Session.
mgSvc := NewMailgunService(mgDomain, mgAPIKey, "")
glSvc := NewGreenlightService(glWebhookURL)
slackSvc := NewSlackService(slackWebhookURL)
// These registration tasks include:
registrationService := newSignupService(
signupServiceOptions{
// Registration tasks:
// (executed concurrently)
tasks: []task{
// posting a WebHook to Greenlight,
glSvc,
// sending a "Welcome Email",
mgSvc,
// sending a Slack message to #signups channel,
slackSvc,
// registering the user for the Zoom meeting,
zoomSvc,
},
},
)
server := newSignupServer(registrationService)
// Register executes a series of tasks in order. If one fails, the remaining tasks are cancelled.
func (sc *SignupService) register(su Signup) error {
for _, task := range sc.tasks {
err := task.run(su)
if err != nil {
return fmt.Errorf("task failed: %q: %v", task.name(), err)
}
}
return nil
}
To register a new task
, create a service struct and implement the task
interface:
package signup
type skywriteService struct {
}
func NewSkyWriteService() *skywriteService {
return &skywriteService{}
}
func (d skywriteService) run(su Signup) error {
return d.skyWrite(su.NameFirst)
}
func (d skywriteService) name() string {
return "dominos service"
}
// SkyWrite sends a drone out to draw someones name in chemtrails.
func (d skywriteService) skyWrite(name string) error {
// Do the thing
return nil
}
Then pass the service to the registration service in function.go
.
func NewServer() {
// ...
registrationService := newSignupService(
// ... other tasks,
// (Order matters!)
NewSkyWriteService()
)
// ...
server := newSignupServer(registrationService)
return server
}
- OS Signups App
- Greenlight Signup API
- Mailgun API
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Please make sure to update tests as appropriate.