Skip to content

Commit a7a0e3e

Browse files
committed
create showtimes service
1 parent c8cea96 commit a7a0e3e

File tree

9 files changed

+412
-0
lines changed

9 files changed

+412
-0
lines changed

showtimes/Dockerfile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# base image
2+
FROM golang:1.22.5-alpine AS builder
3+
RUN adduser -D -g '' elf
4+
WORKDIR /opt/app/
5+
COPY go.mod go.sum ./
6+
RUN go mod download && go mod verify
7+
COPY . .
8+
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -a -installsuffix cgo -o /go/bin/cinema-showtimes ./cmd/app
9+
10+
# build smaller image
11+
FROM alpine:3.17.3
12+
LABEL language="golang"
13+
lABEL org.opencontainers.image.source="https://github.com/mikebellcoder/microservices-docker-go-mongodb"
14+
COPY --from=builder /etc/passwd /etc/passwd
15+
COPY --from=builder --chown=elf:1000 /go/bin/cinema-showtimes /cinema-showtimes
16+
USER elf
17+
ENTRYPOINT [ "./cinema-showtimes" ]

showtimes/cmd/app/handlers.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"net/http"
6+
"time"
7+
8+
"github.com/gorilla/mux"
9+
"github.com/mikebellcoder/microservices-docker-go-mongodb/showtimes/pkg/models"
10+
)
11+
12+
func (app *application) all(w http.ResponseWriter, r *http.Request) {
13+
showtimes, err := app.showtimes.All()
14+
if err != nil {
15+
app.serverError(w, err)
16+
}
17+
18+
b, err := json.Marshal(showtimes)
19+
if err != nil {
20+
app.serverError(w, err)
21+
}
22+
23+
app.infoLog.Println("Showtimes have been listed")
24+
25+
w.Header().Set("Content-Type", "application/json")
26+
w.WriteHeader(http.StatusOK)
27+
w.Write(b)
28+
}
29+
30+
func (app *application) findByID(w http.ResponseWriter, r *http.Request) {
31+
vars := mux.Vars(r)
32+
id := vars["id"]
33+
34+
m, err := app.showtimes.FindByID(id)
35+
if err != nil {
36+
if err.Error() == "ErrNoDocuments" {
37+
app.infoLog.Println("Showtime not found")
38+
return
39+
}
40+
app.serverError(w, err)
41+
}
42+
43+
b, err := json.Marshal(m)
44+
if err != nil {
45+
app.serverError(w, err)
46+
}
47+
48+
app.infoLog.Println("Found a showtime")
49+
50+
w.Header().Set("Content-Type", "application/json")
51+
w.WriteHeader(http.StatusOK)
52+
w.Write(b)
53+
}
54+
55+
func (app *application) findByDate(w http.ResponseWriter, r *http.Request) {
56+
57+
vars := mux.Vars(r)
58+
date := vars["date"]
59+
60+
m, err := app.showtimes.FindByDate(date)
61+
if err != nil {
62+
if err.Error() == "ErrNoDocuments" {
63+
app.infoLog.Println("Shotime not found")
64+
return
65+
}
66+
app.serverError(w, err)
67+
}
68+
69+
b, err := json.Marshal(m)
70+
if err != nil {
71+
app.serverError(w, err)
72+
}
73+
74+
app.infoLog.Println("Date found a showtime")
75+
76+
w.Header().Set("Content-Type", "application/json")
77+
w.WriteHeader(http.StatusOK)
78+
w.Write(b)
79+
}
80+
81+
func (app *application) insert(w http.ResponseWriter, r *http.Request) {
82+
var m models.ShowTime
83+
84+
err := json.NewDecoder(r.Body).Decode(&m)
85+
if err != nil {
86+
app.serverError(w, err)
87+
}
88+
89+
m.CreatedAt = time.Now()
90+
insertResult, err := app.showtimes.Insert(m)
91+
if err != nil {
92+
app.serverError(w, err)
93+
}
94+
95+
app.infoLog.Printf("New showtime has been created, id=%s\n", insertResult.InsertedID)
96+
}
97+
98+
func (app *application) delete(w http.ResponseWriter, r *http.Request) {
99+
vars := mux.Vars(r)
100+
id := vars["id"]
101+
102+
deleteResult, err := app.showtimes.Delete(id)
103+
if err != nil {
104+
app.serverError(w, err)
105+
}
106+
107+
app.infoLog.Printf("Deleted %d showtime(s)\n", deleteResult.DeletedCount)
108+
}

showtimes/cmd/app/helpers.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
6+
"net/http"
7+
"runtime/debug"
8+
)
9+
10+
func (app *application) serverError(w http.ResponseWriter, err error) {
11+
trace := fmt.Sprintf("%s\n%s", err.Error(), debug.Stack())
12+
app.errLog.Output(2, trace)
13+
14+
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
15+
}
16+
17+
func (app *application) clientError(w http.ResponseWriter, status int) {
18+
http.Error(w, http.StatusText(status), status)
19+
}

showtimes/cmd/app/main.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"flag"
6+
"fmt"
7+
"log"
8+
"net/http"
9+
"os"
10+
"time"
11+
12+
"github.com/mikebellcoder/microservices-docker-go-mongodb/showtimes/pkg/models/mongodb"
13+
"go.mongodb.org/mongo-driver/mongo"
14+
"go.mongodb.org/mongo-driver/mongo/options"
15+
)
16+
17+
type application struct {
18+
errLog *log.Logger
19+
infoLog *log.Logger
20+
showtimes *mongodb.ShowTimeModel
21+
}
22+
23+
func main() {
24+
25+
serverAddr := flag.String("serverAddr", "", "HTTP server network address")
26+
serverPort := flag.Int("serverPort", 4000, "HTTP server network port")
27+
mongoURI := flag.String("mongoURI", "mongodb://localhost:27017", "Database hostname url")
28+
mongodDatabase := flag.String("mongoDatabase", "showtimes", "Database name")
29+
enableCredentials := flag.Bool("enableCredentials", false, "Enable the use of credentials for mongo connection")
30+
flag.Parse()
31+
32+
infoLog := log.New(os.Stdout, "INFO\t", log.Ldate|log.Ltime)
33+
errLog := log.New(os.Stderr, "ERROR\t", log.Ldate|log.Ltime|log.Lshortfile)
34+
35+
co := options.Client().ApplyURI(*mongoURI)
36+
if *enableCredentials {
37+
co.Auth = &options.Credential{
38+
Username: os.Getenv("MONGODB_USERNAME"),
39+
Password: os.Getenv("MONGODB_PASSWORD"),
40+
}
41+
}
42+
43+
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
44+
defer cancel()
45+
46+
client, err := mongo.Connect(ctx, co)
47+
if err != nil {
48+
errLog.Fatal(err)
49+
}
50+
51+
defer func() {
52+
if err = client.Disconnect(ctx); err != nil {
53+
panic(err)
54+
}
55+
}()
56+
57+
infoLog.Printf("Database connection established")
58+
59+
app := &application{
60+
infoLog: infoLog,
61+
errLog: errLog,
62+
showtimes: &mongodb.ShowTimeModel{
63+
C: client.Database(*mongodDatabase).Collection("showtimes"),
64+
},
65+
}
66+
67+
serverURI := fmt.Sprintf("%s:%d", *serverAddr, *serverPort)
68+
srv := &http.Server{
69+
Addr: serverURI,
70+
ErrorLog: errLog,
71+
Handler: app.routes(),
72+
IdleTimeout: time.Minute,
73+
ReadTimeout: 5 * time.Second,
74+
WriteTimeout: 10 * time.Second,
75+
}
76+
77+
infoLog.Printf("Starting server on %s", serverURI)
78+
err = srv.ListenAndServe()
79+
errLog.Fatal(err)
80+
}

showtimes/cmd/app/routes.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package main
2+
3+
import "github.com/gorilla/mux"
4+
5+
func (app *application) routes() *mux.Router {
6+
r := mux.NewRouter()
7+
r.HandleFunc("/api/showtimes/", app.all).Methods("GET")
8+
r.HandleFunc("/api/showtimes/{id}", app.findByID).Methods("GET")
9+
r.HandleFunc("/api/showtimes/filter/date/{date}", app.findByDate).Methods("GET")
10+
r.HandleFunc("/api/showtimes/", app.insert).Methods("POST")
11+
r.HandleFunc("/api/showtimes/{id}", app.delete).Methods("DELETE")
12+
13+
return r
14+
}

showtimes/go.mod

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module github.com/mikebellcoder/microservices-docker-go-mongodb/showtimes
2+
3+
go 1.22.5
4+
5+
require (
6+
github.com/gorilla/mux v1.8.1
7+
go.mongodb.org/mongo-driver v1.17.2
8+
)
9+
10+
require (
11+
github.com/golang/snappy v0.0.4 // indirect
12+
github.com/klauspost/compress v1.16.7 // indirect
13+
github.com/montanaflynn/stats v0.7.1 // indirect
14+
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
15+
github.com/xdg-go/scram v1.1.2 // indirect
16+
github.com/xdg-go/stringprep v1.0.4 // indirect
17+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
18+
golang.org/x/crypto v0.26.0 // indirect
19+
golang.org/x/sync v0.8.0 // indirect
20+
golang.org/x/text v0.17.0 // indirect
21+
)

showtimes/go.sum

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
4+
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
5+
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
6+
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
7+
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
8+
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
9+
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
10+
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
11+
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
12+
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
13+
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
14+
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
15+
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
16+
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
17+
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
18+
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
19+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
20+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
21+
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
22+
go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM=
23+
go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
24+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
25+
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
26+
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
27+
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
28+
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
29+
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
30+
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
31+
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
32+
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
33+
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
34+
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
35+
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
36+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
37+
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
38+
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
39+
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
40+
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
41+
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
42+
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
43+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
44+
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
45+
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
46+
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
47+
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
48+
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
49+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
50+
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
51+
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
52+
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

showtimes/pkg/models/models.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package models
2+
3+
import (
4+
"time"
5+
6+
"go.mongodb.org/mongo-driver/bson/primitive"
7+
)
8+
9+
// ShowTime is used to represent showtime profile data
10+
type ShowTime struct {
11+
ID primitive.ObjectID `bson:"_id,omitempty"`
12+
Date string `bson:"data,omitempty"`
13+
CreatedAt time.Time `bson:"created_at,omitempty"`
14+
Movies []string `bson:"movies,omitempty"`
15+
}

0 commit comments

Comments
 (0)