11package api
22
33import (
4+ "context"
5+ "encoding/json"
46 "net/http"
57
6- "github.com/ONSdigital/dp-permissions-api/config"
7-
88 "github.com/ONSdigital/dp-authorisation/v2/authorisation"
9-
9+ "github.com/ONSdigital/dp-permissions-api/config"
1010 "github.com/ONSdigital/dp-permissions-api/models"
11-
11+ "github.com/ONSdigital/log.go/v2/log"
1212 "github.com/gorilla/mux"
1313)
1414
@@ -22,6 +22,20 @@ type API struct {
2222 maximumDefaultLimit int
2323}
2424
25+ type baseHandler func (ctx context.Context , w http.ResponseWriter , r * http.Request ) (* models.SuccessResponse , * models.ErrorResponse )
26+
27+ func contextAndErrors (h baseHandler ) http.HandlerFunc {
28+ return func (w http.ResponseWriter , req * http.Request ) {
29+ ctx := req .Context ()
30+ response , err := h (ctx , w , req )
31+ if err != nil {
32+ writeErrorResponse (ctx , w , err )
33+ return
34+ }
35+ writeSuccessResponse (ctx , w , response )
36+ }
37+ }
38+
2539//Setup function sets up the api and returns an api
2640func Setup (
2741 cfg * config.Config ,
@@ -39,13 +53,82 @@ func Setup(
3953 bundler : bundler ,
4054 }
4155
42- r .HandleFunc ("/v1/roles" , auth .Require (models .RolesRead , api .GetRolesHandler )).Methods (http .MethodGet )
43- r .HandleFunc ("/v1/roles/{id}" , auth .Require (models .RolesRead , api .GetRoleHandler )).Methods (http .MethodGet )
44- r .HandleFunc ("/v1/policies" , auth .Require (models .PoliciesCreate , api .PostPolicyHandler )).Methods (http .MethodPost )
45- r .HandleFunc ("/v1/policies/{id}" , auth .Require (models .PoliciesRead , api .GetPolicyHandler )).Methods (http .MethodGet )
46- r .HandleFunc ("/v1/policies/{id}" , auth .Require (models .PoliciesUpdate , api .UpdatePolicyHandler )).Methods (http .MethodPut )
47- r .HandleFunc ("/v1/policies/{id}" , auth .Require (models .PoliciesDelete , api .DeletePolicyHandler )).Methods (http .MethodDelete )
48- r .HandleFunc ("/v1/permissions-bundle" , api .GetPermissionsBundleHandler ).Methods (http .MethodGet )
56+ r .HandleFunc ("/v1/roles" , auth .Require (models .RolesRead , contextAndErrors ( api .GetRolesHandler ) )).Methods (http .MethodGet )
57+ r .HandleFunc ("/v1/roles/{id}" , auth .Require (models .RolesRead , contextAndErrors ( api .GetRoleHandler ) )).Methods (http .MethodGet )
58+ r .HandleFunc ("/v1/policies" , auth .Require (models .PoliciesCreate , contextAndErrors ( api .PostPolicyHandler ) )).Methods (http .MethodPost )
59+ r .HandleFunc ("/v1/policies/{id}" , auth .Require (models .PoliciesRead , contextAndErrors ( api .GetPolicyHandler ) )).Methods (http .MethodGet )
60+ r .HandleFunc ("/v1/policies/{id}" , auth .Require (models .PoliciesUpdate , contextAndErrors ( api .UpdatePolicyHandler ) )).Methods (http .MethodPut )
61+ r .HandleFunc ("/v1/policies/{id}" , auth .Require (models .PoliciesDelete , contextAndErrors ( api .DeletePolicyHandler ) )).Methods (http .MethodDelete )
62+ r .HandleFunc ("/v1/permissions-bundle" , contextAndErrors ( api .GetPermissionsBundleHandler ) ).Methods (http .MethodGet )
4963
5064 return api
5165}
66+
67+ func writeErrorResponse (ctx context.Context , w http.ResponseWriter , errorResponse * models.ErrorResponse ) {
68+ // override internal server error response to prevent leaking sensitive data
69+ if errorResponse .Status == http .StatusInternalServerError {
70+ http .Error (w , models .InternalServerErrorDescription , http .StatusInternalServerError )
71+ return
72+ }
73+
74+ w .Header ().Set ("Content-Type" , "application/json; charset=utf-8" )
75+ // process custom headers
76+ for key , value := range errorResponse .Headers {
77+ w .Header ().Set (key , value )
78+ }
79+
80+ w .WriteHeader (errorResponse .Status )
81+
82+ jsonResponse , err := json .Marshal (errorResponse )
83+ if err != nil {
84+ responseErr := models .NewError (ctx , err , models .JSONMarshalError , models .ErrorMarshalFailedDescription , nil )
85+ http .Error (w , responseErr .Description , http .StatusInternalServerError )
86+ return
87+ }
88+
89+ _ , err = w .Write (jsonResponse )
90+ if err != nil {
91+ responseErr := models .NewError (ctx , err , models .WriteResponseError , models .WriteResponseFailedDescription , nil )
92+ http .Error (w , responseErr .Description , http .StatusInternalServerError )
93+ return
94+ }
95+ }
96+
97+ func writeSuccessResponse (ctx context.Context , w http.ResponseWriter , successResponse * models.SuccessResponse ) {
98+ w .Header ().Set ("Content-Type" , "application/json; charset=utf-8" )
99+ // process custom headers
100+ for key , value := range successResponse .Headers {
101+ w .Header ().Set (key , value )
102+ }
103+ w .WriteHeader (successResponse .Status )
104+
105+ _ , err := w .Write (successResponse .Body )
106+ if err != nil {
107+ responseErr := models .NewError (ctx , err , models .WriteResponseError , models .WriteResponseFailedDescription , nil )
108+ http .Error (w , responseErr .Description , http .StatusInternalServerError )
109+ return
110+ }
111+ }
112+
113+ func handleInvalidQueryParameterError (ctx context.Context , err error , name string , value string ) * models.ErrorResponse {
114+ logData := log.Data {name : value }
115+ return models .NewErrorResponse (http .StatusBadRequest ,
116+ nil ,
117+ models .NewError (ctx , err , models .InvalidQueryParameterError , models .InvalidQueryParameterDescription , logData ),
118+ )
119+ }
120+
121+ func handleBodyMarshalError (ctx context.Context , err error , name string , value interface {}) * models.ErrorResponse {
122+ logData := log.Data {name : value }
123+ return models .NewErrorResponse (http .StatusInternalServerError ,
124+ nil ,
125+ models .NewError (ctx , err , models .JSONMarshalError , models .MarshalFailedDescription , logData ),
126+ )
127+ }
128+
129+ func handleBodyUnmarshalError (ctx context.Context , err error ) * models.ErrorResponse {
130+ return models .NewErrorResponse (http .StatusBadRequest ,
131+ nil ,
132+ models .NewError (ctx , err , models .JSONUnmarshalError , models .UnmarshalFailedDescription , nil ),
133+ )
134+ }
0 commit comments