Masih menggunakan webapp dari modul sebelumnya, pada modul ini kita akan melakukan persiapan untuk membuat Web API.
Pertama buat folder api dibawah folder cmd.
Buat file cmd/api/utilities.go, yang akan berisi fungsi helper JSON.
package main
import (
"encoding/json"
"errors"
"io"
"net/http"
)
func (app *application) writeJSON(w http.ResponseWriter, status int, data interface{}, wrap ...string) error {
// out will hold the final version of the json to send to the client
var out []byte
// decide if we wrap the json payload in an overall json tag
if len(wrap) > 0 {
// wrapper
wrapper := make(map[string]interface{})
wrapper[wrap[0]] = data
jsonBytes, err := json.Marshal(wrapper)
if err != nil {
return err
}
out = jsonBytes
} else {
// wrapper
jsonBytes, err := json.Marshal(data)
if err != nil {
return err
}
out = jsonBytes
}
// set the content type & status
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
// write the json out
_, err := w.Write(out)
if err != nil {
return err
}
return nil
}
func (app *application) errorJSON(w http.ResponseWriter, err error, status ...int) {
statusCode := http.StatusBadRequest
if len(status) > 0 {
statusCode = status[0]
}
type jsonError struct {
Message string `json:"message"`
}
theError := jsonError{
Message: err.Error(),
}
_ = app.writeJSON(w, statusCode, theError, "error")
}
func (app *application) readJSON(w http.ResponseWriter, r *http.Request, data interface{}) error {
maxBytes := 1024 * 1024 // one megabyte
r.Body = http.MaxBytesReader(w, r.Body, int64(maxBytes))
dec := json.NewDecoder(r.Body)
dec.DisallowUnknownFields()
// attempt to decode the data
err := dec.Decode(data)
if err != nil {
return err
}
// make sure only one JSON value in payload
err = dec.Decode(&struct{}{})
if err != io.EOF {
return errors.New("body must only contain a single JSON value")
}
return nil
}
Berikutnya kita akan buat file main, db, routes, api-handlers.
File cmd/api/main.go.
package main
import (
"flag"
"fmt"
"log"
"net/http"
"webapp/pkg/repository"
"webapp/pkg/repository/dbrepo"
)
const port = 8090
type application struct {
DSN string
DB repository.DatabaseRepo
Domain string
JWTSecret string
}
func main() {
var app application
flag.StringVar(&app.Domain, "domain", "example.com", "Domain for application, e.g. company.com")
flag.StringVar(&app.DSN, "dsn", "host=localhost port=5432 user=postgres password=postgres dbname=users sslmode=disable timezone=UTC connect_timeout=5", "Posgtres connection")
flag.StringVar(&app.JWTSecret, "jwt-secret", "2dce505d96a53c5768052ee90f3df2055657518dad489160df9913f66042e160", "signing secret")
flag.Parse()
conn, err := app.connectToDB()
if err != nil {
log.Fatal(err)
}
defer conn.Close()
app.DB = &dbrepo.PostgresDBRepo{DB: conn}
log.Printf("Starting api on port %d\n", port)
err = http.ListenAndServe(fmt.Sprintf(":%d", port), app.routes())
if err != nil {
log.Fatal(err)
}
}
File cmd/api/db.go.
package main
import (
"database/sql"
"log"
_ "github.com/jackc/pgconn"
_ "github.com/jackc/pgx/v4"
_ "github.com/jackc/pgx/v4/stdlib"
)
func openDB(dsn string) (*sql.DB, error) {
db, err := sql.Open("pgx", dsn)
if err != nil {
return nil, err
}
err = db.Ping()
if err != nil {
return nil, err
}
return db, nil
}
func (app *application) connectToDB() (*sql.DB, error) {
connection, err := openDB(app.DSN)
if err != nil {
return nil, err
}
log.Println("Connected to Postgres!")
return connection, nil
}
File cmd/api/routes.go.
package main
import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func (app *application) routes() http.Handler {
mux := chi.NewRouter()
// register middleware
mux.Use(middleware.Recoverer)
// mux.Use(app.enableCORS)
// authentication routes - auth handler, refresh
mux.Post("/auth", app.authenticate)
mux.Post("/refresh-token", app.refresh)
// test handler
mux.Get("/test", func(w http.ResponseWriter, r *http.Request){
var payload = struct {
Message string `json:"message"`
}{
Message: "hello, world",
}
_ = app.writeJSON(w, http.StatusOK, payload)
})
// protected routes
mux.Route("/users", func(mux chi.Router) {
// use auth middleware
mux.Get("/", app.allUsers)
mux.Get("/{userID}", app.getUser)
mux.Delete("/{userID}", app.deleteUser)
mux.Put("/", app.insertUser)
mux.Patch("/", app.updateUser)
})
return mux
}
File cmd/api/api-handlers.go.
package main
import "net/http"
func (app *application) authenticate(w http.ResponseWriter, r *http.Request) {
}
func (app *application) refresh(w http.ResponseWriter, r *http.Request) {
}
func (app *application) allUsers(w http.ResponseWriter, r *http.Request) {
}
func (app *application) getUser(w http.ResponseWriter, r *http.Request) {
}
func (app *application) updateUser(w http.ResponseWriter, r *http.Request) {
}
func (app *application) deleteUser(w http.ResponseWriter, r *http.Request) {
}
func (app *application) insertUser(w http.ResponseWriter, r *http.Request) {
}
Selanjutnya mari Kita lakukan test. Pertama jalankan server
$ go run ./cmd/api
2022/10/31 18:41:38 Connected to Postgres!
2022/10/31 18:41:38 Starting api on port 8090
Buka command prompt kedua, lalu lakukan test menggunakan curl untuk routes test. Sesuai ekspektasi, kita memperoleh return JSON {“message”:”hello, world”}
$ curl http://localhost:8090/test
{"message":"hello, world"}
Sampai disini persiapan web API tahap awal sudah selesai. Pada modul selanjutnya kita akan mulai menambahkan fungsi JWT authentication.