Goã®APIãµã¼ãã¼ã§middlewareãé©ç¨ããæã«aliceã使ã£ã¦æ¥½ããã
Goã§APIãµã¼ããä½ã£ã¦ããæã«middlewareãé©ç¨ãããã¨ã¯ããããã¨æãã®ã§ãããæ°ãå¤ãã¨ä¸ã®ããã«ã´ãã´ãããæãã«ãªãã¨æãã¾ãã
func main() { mux := http.NewServeMux() mux.HandleFunc("/handler1", handler1) handler := middle1(middle2(mux)) log.Fatal(http.ListenAndServe(":8080", handler)) }
ãã®ä¾ã§ã¯middlewareã2ã¤ã ããªãã§ããã§æ¸ãã§ã¾ãããå¢ãã¦ããã¨ã´ãã´ã度ã¯å¢å¤§ãã¦ããã¨æãã¾ãã
ãã®é¨åããªããããæ¹æ³ãªãããæ¢ãã¦ããããã£ã±ãããã¾ããã
æ©éã試ãã¦ã¿ã¾ããã
ã¤ã³ã¹ãã¼ã«
go get github.com/justinas/alice
aliceã使ã£ããµã³ãã«
alice.New(
ã®é¨åãããã§ãããã風ã«æ軽ã«middlewareãé©ç¨ã§ããããã«ãªãã
func main() { mux := http.NewServeMux() mux.HandleFunc("/handler1", handler1) handler := alice.New(middle1, middle2).Then(mux) log.Fatal(http.ListenAndServe(":8080", handler)) } func middle1(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Println("middle1 start") next.ServeHTTP(w, r) fmt.Println("middle1 end") }) } func middle2(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Println("middle2 start") next.ServeHTTP(w, r) fmt.Println("middle2 end") }) }
å®è¡çµæ
ä¸è¨ã®ãµã¼ããèµ·åãã¦ãå¥ã¿ã¼ããã«ãã以ä¸ã®ããã«ãªã¯ã¨ã¹ããé£ã°ãã
curl http://localhost:8080/handler1
ãµã¼ãå´ã®ãã°ã«ä»¥ä¸ã®ããã«è¡¨ç¤ºãããç¡äºmiddlewareãé©ç¨ããã¦ãããã¨ã確èªã§ããã 便å©ã
middle1 start middle2 start middle2 end middle1 end
Goã®APIãµã¼ãã®ã¬ã¹ãã³ã¹ãgzipå§ç¸®ãã
ä»ãä»äºã§ä½ã£ã¦ããGoã§ä½ãããAPIãµã¼ãã¯æ¯è¼çãã¬ã¹ãã³ã¹ã巨大ãªãã®ãå¤ããgzipå§ç¸®ããæ¹ãè¯ãããã«æããã
APIãµã¼ãã¯GCPä¸ã®API gatewayãå段ã«ããããã®å¾ãã§Cloud Runã§å®éã®å¦çãåãã¦ããæ§æã æåã¯API gatewayã¨ãã«gzipå§ç¸®ããæ©è½ã¨ãããããã¨ãæã£ã¦ãããããããæ©è½ã¯ãªãã¿ãããªã®ã§APIãµã¼ãå´ã§å®è£ ãã¦ã¿ãã
使ã£ãã©ã¤ãã©ãª
ä¸ã®ãªã³ã¯å ã®ãã®ã使ã£ãã åºæ¬çã«ã¯1024ãã¤ããè¶ ããã¬ã¹ãã³ã¹ã§ãªãã¨gzipå§ç¸®ããªãããã«ãªã£ã¦ããã®ã§ãå°ãã大ããã®ã¬ã¹ãã³ã¹ã®æã®å§ç¸®ã»è§£åã«ããæ§è½å£åã¿ãããªãã¨ã¯å°ãªãã¨æãã
ã¤ã³ã¹ãã¼ã«
go get github.com/klauspost/compress
çµã¿è¾¼ã¿ä¾
package main import ( "log" "net/http" "github.com/klauspost/compress/gzhttp" ) func main() { mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte("{\"test\": \"--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\"}")) }) handler := gzhttp.GzipHandler(handler) log.Fatal(http.ListenAndServe(":8080", handler)) }
åä½ç¢ºèª
curlã§ä»¥ä¸ã®ããã«ãã¦ç¢ºèªã
--compressed
ãªãã·ã§ã³ãä»ãããã¨ã§Accept-Encoding: gzip
ã¿ãããªæããªã模æ§ã
ãªã¯ã¨ã¹ã
curl -v --compressed http://localhost:8080/
ã¬ã¹ãã³ã¹
ã¬ã¹ãã³ã¹ãããã¼ã«Content-Encoding: gzip
ãæå³ã©ããã«ä»ãã¦ããã®ã§ãgzipå§ç¸®ããã¦ãããã¨ããããã
* Trying 127.0.0.1:8080... * Connected to localhost (127.0.0.1) port 8080 (#0) > GET / HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.86.0 > Accept: */* > Accept-Encoding: deflate, gzip, br, zstd > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Content-Encoding: gzip < Content-Type: application/json < Vary: Accept-Encoding < Date: Sun, 10 Dec 2023 11:15:36 GMT < Content-Length: 48 < {"test": "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------* Connection #0 to host localhost left intact ------------"}%
Cloud Run jobsã試ãã¦ã¿ã
ã¿ã¤ãã«ã©ãããCloud Run jobsã使ã£ããã¨ããªãã£ãã®ã§è©¦ãã¦ã¿ãã
æé
æ¤è¨¼ç¨ã®ã¢ããªä½æ
main.go
package main import "fmt" func main() { fmt.Println("start process") fmt.Println("something process") fmt.Println("finish process") }
Dockerfile
FROM golang:1.21-alpine AS builder WORKDIR /usr/local/src/ ADD go.mod ./ RUN go mod download ADD . . RUN go build -o /go/bin/app ./main.go FROM alpine:latest COPY --from=builder /go/bin/app / CMD ["/app"]
åä½ç¢ºèª
ä¸ã®ããã«3ã¤ã®æååã表示ãããããOK
# åä½ç¢ºèª > docker build . -t test-app > docker run --rm test-app start process something process finish process
ã¤ã¡ã¼ã¸ã®push
artifact registoryã«ã¬ãã¸ããªãä½æããã¤ã¡ã¼ã¸ãpushãã
> PROJECT=$(gcloud config get-valud project) > REGION=$(gcloud config get-value compute/region) # dockerã¨ã®é£æº(docker pushããããã«å¿ è¦) > gcloud auth configure-docker asia-northeast1-docker.pkg.dev # ã¬ãã¸ããªã®ä½æ > gcloud artifacts repositories create docker-repo --repository-format=docker --location="${REGION}" --description="Docker repository" # ã¬ãã¸ããªã®ãªã¹ãç¢ºèª > gcloud artifacts repositories list # tagä»ããã¦push > REPO="asia-northeast1-docker.pkg.dev/${PROJECT}/docker-repo" > docker tag test-app "${REPO}/test-app" > docker push "${REPO}/test-app"
ã¸ã§ããä½æããå®è¡
> gcloud run jobs create sample-job --image "${REPO}/test-app:latest" --region "${REGION}" > gcloud run jobs execute sample-job --region "${REGION}" # å®è¡çµæã®ç¢ºèª > gcloud beta run jobs logs read sample-job --region "${REGION}" 2023-10-15 04:09:19 start process 2023-10-15 04:09:19 something process 2023-10-15 04:09:19 finish process
ã¨ãããããjobãåä½ããããã¨ã¯ã§ããã å®éã«ã¯Cloud Schedulerã§ã®å®æå®è¡ã¨ã¯ä½ãã®Pub/Subãããã§ã®ã¤ãã³ãé§åããããã®ã使ãæ¹ã«ãªããã ã¨ã¯æãã
å¾çä»ã
gcloud run jobs delete sample-job --region "${REGION}" gcloud artifacts repositories delete docker-repo --location "${REGION}"
åè
GCP Cloud Runã§Dockerfileãä½ããªãã¦ããããã¤ãã¦åä½ãå¯è½ãæ¤è¨¼
Cloud Runã§ä½ãã®ã¢ããªããããã¤ããæã«ã¯ã³ã³ããã¤ã¡ã¼ã¸ãä½ã£ãããgithubã¨é£æºãããããå¿ è¦ããããã¨èª¤è§£ãã¦ãã¾ãããããããã¤ã³ãã³ãã®--sourceãªãã·ã§ã³ã使ç¨ãããã¨ã§ãã¼ã«ã«ã®ã½ã¼ã¹ãããããã¤ã¾ã§å¯è½ã¨ããè¨äºãèªãã§ãèªåã§ã試ãã¦ã¿ã¾ããã
æé
æ¤è¨¼ç¨ã®ã¢ããªä½æ
ã¢ã¯ã»ã¹ããã¨JSONãè¿å´ããã ãã®æ¤è¨¼ç¨APIãµã¼ããä½æãã¾ãã
main.go
package main import ( "encoding/json" "log" "net/http" "os" ) type Hello struct { Title string Desc string Ver string } func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(Hello{Title: "Hello", Desc: "BuildPack", Ver: "0.0.1"}) }) port := os.Getenv("PORT") log.Printf("Listening on %v", port) log.Fatal(http.ListenAndServe(":"+port, nil)) }
åä½ç¢ºèª
ã¾ãã¯ãã¼ã«ã«ã§åä½ç¢ºèªãã¾ãã ã¿ã¼ããã«ãéãã¦ä¸è¨ã®ã³ãã³ãã§APIãµã¼ããèµ·åã
export PORT=8080 go run main.go
å¥ã®ã¿ã¼ããã«ãéããAPIãµã¼ãã«ãªã¯ã¨ã¹ããæãã¦ã¿ã¾ãã
> curl http://localhost:8080/ {"Title":"Hello","Desc":"BuildPack","Ver":"0.0.1"}
æå³ããã¬ã¹ãã³ã¹ãè¿å´ããã¦ãã¾ããã
Cloud Runã¸ã®ãããã¤
以ä¸ã®ã³ãã³ãã§cloudrunã¸ãããã¤ããã ãã¤ã³ãã¯--sourceãªãã·ã§ã³ã
PORTçªå·ã«ã¤ãã¦ã¯èªåçã«PORTç°å¢å¤æ°ãè¨å®ããã¦ãããããã©ã«ãã§8080ãè¨å®ããã¦ããçºãããã§ã¯ç¹ã«æå®ããªãã
gcloud run deploy sample-app --region asia-northeast1 --platform managed --allow-unauthenticated --source .
ãã°ããããã¨ãããã¤å®äºã¨å ±ã«URLã表示ãããã¨æãã®ã§ããã«ãªã¯ã¨ã¹ããæãã¾ãã
Service URL: https://sample-app-aoytzwylua-an.a.run.app > curl https://sample-app-aoytzwylua-an.a.run.app main {"Title":"Hello","Desc":"BuildPack","Ver":"0.0.1"}
ç¡äºã«ãããã¤ã§ãã¦ãã¾ããã
ææ³
è£å´ã§ã¯buildpackã«ãããã³ã³ããã¤ã¡ã¼ã¸ãçæããããããCloud Runã«ãããã¤ããã¦ããããã§ããã 便å©ã
entã§group byã§éç´ããçµæã®countã§order byããæ¹æ³
ã¿ã¤ãã«ã©ããã
select count(*) as cnt from items group by type order by cnt desc
ã¿ããã«group byãã¦æå®ããé ç®æ¯ã«ä»¶æ°ã§ä¸¦ã³æ¿ããããã¨ããã±ã¼ã¹ãããå ´åãentã§ã¯ã©ããã£ããè¨è¿°ã§ããã®ã調ã¹ãã
æ¬å½ã«ãããæ£è§£ãªã®ãã¯ããããªãã£ããã©ãä¸å¿ä¸ã®ãããªã¯ã¨ãªãentã§çºè¡ãããã¨ã¯ã§ããã
var results []struct { Count int Type string } err = r.ent().Item.Query().Where(apply).Order( func(s *sql.Selector) { s.OrderExpr(sql.ExprP("Count(*) Desc")) }, ).GroupBy(item.FieldType).Aggregate(ent.Count()).Scan(ctx, &results)
ã§ãããã£ã¨ããããæ¹ãããããã§ãå°ãã¢ã¤ã«ã
追è¨: ç¹ã«è©¦ãã¦ã¯ããªããã©ãentã§ã³ã¼ãçæããæã«ãã§ã«ä¸è¨ã®ãããªãã®ãçæããã¦ãã模æ§ã ã ãããèªåã§ä¸è¨ã®ãããªã³ã¼ãã¯è¨è¿°ããå¿ è¦ã¯ãªãããã
åè
yarnã§ãã¼ã¸ã§ã³ãåãæ¿ããããªãç¾è±¡ã¸ã®å¯¾å¿
yarnã³ãã³ãã«ã¤ãã¦ã¯èªåã®PCã§ã¯ç¹ã«v3ç³»ã®ãã¦ãã¦ç¹ã«ä¸ä¾¿ã¯æãã¦ãªãã¦ãã®ã¾ã¾ã ã£ãã ãã ãä»äºé¢é£ã®ããã³ãã¨ã³ããv1ç³»ã ã£ãã®ã§ãä»äºã®æã ãåãæ¿ããå¿ è¦ãåºã¦ããã
æè¿ã®yarnã¯èªåã§ãã¼ã¸ã§ã³ãåãæ¿ãå¯è½ãªããã§ãæ©éåãæ¿ãã¦ã¿ã¦ãåãæ¿ãããªãã£ãã ä¸ã®ãããªç¶æ³ã
yarn set version 1.22.19 yarn -v 3.4.1
ãªãã ã¼ãã¨æããªããã調ã¹ã¦ããçµæã$HOMEã®.yarnrcã¨.yarnrc.ymlãåå ã£ã½ããã¨ãããã£ãã
æãåã£ã¦$HOMEã®.yarnrcã¨.yarnrc.ymlãåé¤ãã¦ã¿ããããã£ã¨æå³ã©ããåä½ããã 1æéãããããã ãã§æéã溶ãã¦ãã¾ã£ãã»ã»ã»
yarn set version 1.22.19 yarn -v 1.22.19
viteã§éçºãµã¼ããèµ·åãã¦ãä½ã表示ãããªããªãç¾è±¡ã¸ã®å¯¾å¿
ä»äºã®ããã³ãã¨ã³ãéçºã§ã¯viteã使ç¨ãã¦ãã¾ãã
ãã æè¿viteã³ãã³ãã§éçºãµã¼ããèµ·åãã¦ãä½ã表示ãããªããªãï¼ç»é¢ã¯çã£ç½ï¼ãã¨ããäºè±¡ã«ééãã¾ããã chromeã®ã³ã³ã½ã¼ã«ã確èªããã¨ä»¥ä¸ã®ãããªæååã ãã表示ããã¦ãã¾ããã
Failed to load resource: the server responded with a status of 504 (Outdated Optimize Dep)
対å¿1
ã¨ãããããåã¤ã³ã¹ãã¼ã«ãããã©ãã«ããªããããã¨æãã以ä¸ã®ãããªæé ã§åã¤ã³ã¹ãã¼ã«ããviteãèµ·åãã¾ããã
rm -fr node_modules yarn install yarn dev (viteã³ãã³ããå©ãã¦ããã ãï¼
ããã§ç»é¢ã表示ããããã§ãããã§ããã»ã»ã»ã¨ã¯ãªãã¾ããã§ããã ä¸åº¦ãéçºãµã¼ããæ¢ããã¨ã¾ãããã®æé ã§èµ·åããªãã¨ä½ã表示ãããªããã¨ããç¶æ ã§ãã ããã§ã¯ãã©ã¤ãã¨ãããã¨ã§ããã«èª¿æ»ã
対å¿2
çµè«ã¨ãã¦ã¯vite --forceã§ã¨ããããã¯è§£æ±ºãã¾ããã
vite --force
æ ¹æ¬çãªåå ã«ã¤ãã¦ã¯ãããããããã¨ããã®ãæ£ç´ãªã¨ããã
--forceãªãã·ã§ã³ã¯å¼·å¶çã«åãã³ãã«ãããæå®ã®ããã§ãã ãã ããã®ãªãã·ã§ã³ãæå®ããã¨viteã®è¯ãããªãããã¨ã«ãªãããã»ã»ã»