From 3d288dacf0ff0304955977cda70cb300181233ca Mon Sep 17 00:00:00 2001 From: songsc Date: Thu, 25 Feb 2021 20:00:24 -0500 Subject: [PATCH 1/2] added twilio sms api --- api/notification-service.yaml | 38 ++++++++++++++++++ cmd/server/main.go | 5 ++- internal/config/config.go | 18 +++++++++ internal/service/api_sms_service.go | 61 +++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 internal/service/api_sms_service.go diff --git a/api/notification-service.yaml b/api/notification-service.yaml index b6573f2..108f07b 100644 --- a/api/notification-service.yaml +++ b/api/notification-service.yaml @@ -74,6 +74,33 @@ paths: schema: $ref: '#/components/schemas/Error' + /sms/send: + post: + summary: Send an SMS + operationId: sendSMS + tags: + - sms + requestBody: + description: Parameters of the message to send + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SendSMSRequest' + responses: + 200: + description: OK + content: + application/json: + schema: + type: string + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /notification/slack/send: post: summary: Send a Slack message @@ -254,6 +281,17 @@ components: description: Schedule these mesages to go out at the time specified by this UNIX timestamp format: int64 + SendSMSRequest: + type: object + required: + - recipient + - message + properties: + recipient: + type: string + message: + type: string + SlackRecipient: type: object required: diff --git a/cmd/server/main.go b/cmd/server/main.go index 7345c79..41277d2 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -44,13 +44,16 @@ func main() { EmailApiService := service.NewEmailApiService(config) EmailApiController := server.NewEmailApiController(EmailApiService) + SmsApiService := service.NewSmsApiService(config) + SmsApiController := server.NewSmsApiController(SmsApiService) + HealthApiService := service.NewHealthApiService(config) HealthApiController := server.NewHealthApiController(HealthApiService) NotificationApiService := service.NewNotificationApiService(config) NotificationApiController := server.NewNotificationApiController(NotificationApiService) - router := server.NewRouter(EmailApiController, HealthApiController, NotificationApiController) + router := server.NewRouter(EmailApiController, SmsApiController, HealthApiController, NotificationApiController) serverAddress := fmt.Sprintf("0.0.0.0:%d", config.Port) server := &http.Server{Addr: serverAddress, Handler: router} diff --git a/internal/config/config.go b/internal/config/config.go index a6cfc7b..2428bfe 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -11,6 +11,9 @@ type Config struct { Port int SendgridAPIKey string SlackAPIKey string + TwilioAccID string + TwilioAuthToken string + TwilioPhoneNumber string GracefulShutdownTimeout time.Duration StructuredLogging bool } @@ -22,6 +25,9 @@ const ( Port SendgridAPIKey SlackAPIKey + TwilioAccID + TwilioAuthToken + TwilioPhoneNumber GracefulShutdownTimeout StructuredLogging ) @@ -44,6 +50,15 @@ func loadConfig() *Config { viper.SetDefault(SlackAPIKey, "") viper.BindEnv(SlackAPIKey, "SLACK_API_KEY") + viper.SetDefault(TwilioAccID, "") + viper.BindEnv(TwilioAccID, "TWILIO_ACC_ID") + + viper.SetDefault(TwilioAuthToken, "") + viper.BindEnv(TwilioAuthToken, "TWILIO_AUTH_TOKEN") + + viper.SetDefault(TwilioPhoneNumber, "") + viper.BindEnv(TwilioPhoneNumber, "TWILIO_PHONE_NUMBER") + viper.SetDefault(GracefulShutdownTimeout, "10") viper.BindEnv(GracefulShutdownTimeout, "GRACEFUL_SHUTDOWN_TIMEOUT_SECONDS") @@ -54,6 +69,9 @@ func loadConfig() *Config { Port: viper.GetInt(Port), SendgridAPIKey: viper.GetString(SendgridAPIKey), SlackAPIKey: viper.GetString(SlackAPIKey), + TwilioAccID: viper.GetString(TwilioAccID), + TwilioAuthToken: viper.GetString(TwilioAuthToken), + TwilioPhoneNumber: viper.GetString(TwilioPhoneNumber), GracefulShutdownTimeout: viper.GetDuration(GracefulShutdownTimeout), StructuredLogging: viper.GetBool(StructuredLogging), } diff --git a/internal/service/api_sms_service.go b/internal/service/api_sms_service.go new file mode 100644 index 0000000..d42c279 --- /dev/null +++ b/internal/service/api_sms_service.go @@ -0,0 +1,61 @@ +package service + +import ( + "context" + "fmt" + "net/http" + "net/url" + "strings" + + "github.com/commitdev/zero-notification-service/internal/config" + "github.com/commitdev/zero-notification-service/internal/server" +) + +// EmailApiService is a service that implents the logic for the EmailApiServicer +// This service should implement the business logic for every endpoint for the EmailApi API. +// Include any external packages or services that will be required by this service. +type SmsApiService struct { + config *config.Config +} + +// NewSmsApiService creates a default api service +func NewSmsApiService(c *config.Config) server.SmsApiServicer { + return &SmsApiService{c} +} + +// SendSMS - Send an email +func (s *SmsApiService) SendSMS(ctx context.Context, sendSMSRequest server.SendSmsRequest) (server.ImplResponse, error) { + // Set initial variables + accountSid := s.config.TwilioAccID + authToken := s.config.TwilioAuthToken + urlStr := "https://api.twilio.com/2010-04-01/Accounts/" + accountSid + "/Messages.json" + + // Build out the data for our message + v := url.Values{} + v.Set("To", sendSMSRequest.Recipient) + v.Set("From", s.config.TwilioPhoneNumber) + v.Set("Body", sendSMSRequest.Message) + rb := *strings.NewReader(v.Encode()) + + // Create Client + client := &http.Client{} + + req, _ := http.NewRequest("POST", urlStr, &rb) + req.SetBasicAuth(accountSid, authToken) + req.Header.Add("Accept", "application/json") + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + // Make request + resp, err := client.Do(req) + fmt.Print(resp.Status) + + if err != nil { + fmt.Printf("Error sending SMS: %v\n", resp) + return server.Response(http.StatusInternalServerError, nil), fmt.Errorf("Unable to send SMS: %v", err) + } + if !(resp.StatusCode >= 200 && resp.StatusCode <= 299) { + fmt.Printf("Failure from Twilio when sending SMS: %v", resp) + return server.Response(http.StatusBadRequest, "Error sending SMS"), nil + } + return server.Response(http.StatusOK, "SMS Sent"), nil +} From 1d159c7249c41e95dca870dc8745a4a633d980e2 Mon Sep 17 00:00:00 2001 From: songsc Date: Thu, 25 Feb 2021 20:25:39 -0500 Subject: [PATCH 2/2] wrap response in json --- api/notification-service.yaml | 6 ++++++ internal/service/api_sms_service.go | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/api/notification-service.yaml b/api/notification-service.yaml index 108f07b..598ff91 100644 --- a/api/notification-service.yaml +++ b/api/notification-service.yaml @@ -292,6 +292,12 @@ components: message: type: string + SendSMSResponse: + type: object + properties: + message: + type: string + SlackRecipient: type: object required: diff --git a/internal/service/api_sms_service.go b/internal/service/api_sms_service.go index d42c279..bd55700 100644 --- a/internal/service/api_sms_service.go +++ b/internal/service/api_sms_service.go @@ -55,7 +55,7 @@ func (s *SmsApiService) SendSMS(ctx context.Context, sendSMSRequest server.SendS } if !(resp.StatusCode >= 200 && resp.StatusCode <= 299) { fmt.Printf("Failure from Twilio when sending SMS: %v", resp) - return server.Response(http.StatusBadRequest, "Error sending SMS"), nil + return server.Response(http.StatusBadRequest, server.SendSmsResponse{Message: "Error sending SMS"}), nil } - return server.Response(http.StatusOK, "SMS Sent"), nil + return server.Response(http.StatusOK, server.SendSmsResponse{Message: "SMS Sent"}), nil }