CORS Middleware
Pertama, kita akan mengimplementasikan CORS middleware.
Buat file baru cmd/api/api-middleware.go, lalu tambahkan kode berikut.
package main
import "net/http"
func (app *application) enableCORS(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
w.Header().Set("Access-Control-Allow-Origin", "http://localhost:8090")
if r.Method == "OPTIONS" {
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Methods", "GET,POST,PUT,PATCH,DELETE,OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, X-CSRF-Token, Authorization")
return
} else {
next.ServeHTTP(w, r)
}
})
}
func (app *application) authRequired(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
_, _, err := app.getTokenFromHeaderAndVerify(w, r)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
return
})
}
Kemudian untuk test, kita buat file cmd/api/api-middleware_test.go, lalu gunakan kode berikut untuk fungsi testing.
package main
import (
"net/http"
"net/http/httptest"
"testing"
)
func Test_app_enableCORS(t *testing.T) {
nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
var tests = []struct {
name string
method string
expectHeader bool
}{
{"preflight", "OPTIONS", true},
{"get", "GET", false},
}
for _, e := range tests {
handlerToTest := app.enableCORS(nextHandler)
req := httptest.NewRequest(e.method, "http://testing", nil)
rr := httptest.NewRecorder()
handlerToTest.ServeHTTP(rr, req)
if e.expectHeader && rr.Header().Get("Access-Control-Allow-Credentials") == "" {
t.Errorf("%s: expected header, but did not find it", e.name)
}
if !e.expectHeader && rr.Header().Get("Access-Control-Allow-Credentials") != "" {
t.Errorf("%s: expected no header, but got one", e.name)
}
}
}
Jika kita test middleware CORS diatas dengan perintah berikut, sesuai ekspektasi, test berhasil.
$ go test -v -run Test_app_enableCORS
=== RUN Test_app_enableCORS
--- PASS: Test_app_enableCORS (0.00s)
PASS
ok webapp/cmd/api 0.292s
authRequired Middleware
Selanjutnya kita akan membuat test untuk authRequired test. Buka file cmd/api/api-middleware_test.go, lalu tambahkan fungsi Test_app_authRequired, seperti code dibawah.
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"webapp/pkg/data"
)
func Test_app_enableCORS(t *testing.T) {
nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
var tests = []struct {
name string
method string
expectHeader bool
}{
{"preflight", "OPTIONS", true},
{"get", "GET", false},
}
for _, e := range tests {
handlerToTest := app.enableCORS(nextHandler)
req := httptest.NewRequest(e.method, "http://testing", nil)
rr := httptest.NewRecorder()
handlerToTest.ServeHTTP(rr, req)
if e.expectHeader && rr.Header().Get("Access-Control-Allow-Credentials") == "" {
t.Errorf("%s: expected header, but did not find it", e.name)
}
if !e.expectHeader && rr.Header().Get("Access-Control-Allow-Credentials") != "" {
t.Errorf("%s: expected no header, but got one", e.name)
}
}
}
func Test_app_authRequired(t *testing.T) {
nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
testUser := data.User{
ID: 1,
FirstName: "Admin",
LastName: "User",
Email: "admin@example.com",
}
tokens, _ := app.generateTokenPair(&testUser)
var tests = []struct {
name string
token string
expectAuthorized bool
setHeader bool
}{
{name: "valid token", token: fmt.Sprintf("Bearer %s", tokens.Token), expectAuthorized: true, setHeader: true},
{name: "no token", token: "", expectAuthorized: false, setHeader: false},
{name: "invalid token", token: fmt.Sprintf("Bearer %s", expiredToken), expectAuthorized: false, setHeader: true},
}
for _, e := range tests {
req, _ := http.NewRequest("GET", "/", nil)
if e.setHeader {
req.Header.Set("Authorization", e.token)
}
rr := httptest.NewRecorder()
handlerToTest := app.authRequired(nextHandler)
handlerToTest.ServeHTTP(rr, req)
if e.expectAuthorized && rr.Code == http.StatusUnauthorized {
t.Errorf("%s: got code 402, and should not have", e.name)
}
if !e.expectAuthorized && rr.Code != http.StatusUnauthorized {
t.Errorf("%s: did not get code 401, and should have", e.name)
}
}
}
Jika kita lakukan test dengan perintah dibawah, sesuai ekspektasi test berhasil.
$ go test -v -run Test_app_authRequired
=== RUN Test_app_authRequired
--- PASS: Test_app_authRequired (0.00s)
PASS
ok webapp/cmd/api 0.292s