Skip to content

Commit

Permalink
Improving REST API. Building docker images.
Browse files Browse the repository at this point in the history
  • Loading branch information
seagiv committed Sep 7, 2020
1 parent 9f71a6f commit 1c47e68
Show file tree
Hide file tree
Showing 15 changed files with 444 additions and 280 deletions.
12 changes: 4 additions & 8 deletions Dockerfile → Dockerfile.apiserver
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,15 @@ FROM build_base AS server_builder
COPY . .

# And compile the project
RUN make build
RUN make apiserver

#In this last stage, we start from a fresh Alpine image, to reduce the image size and not ship the Go compiler in our production artifacts.
FROM alpine AS dash-backend
FROM alpine AS explorer-api

# Finally we copy the statically compiled Go binary.
COPY --from=server_builder /go/src/github.com/spacemeshos/explorer-backend/build/explorer-backend /bin/explorer-backend
COPY --from=server_builder /go/src/github.com/spacemeshos/explorer-backend/build/apiserver /bin/explorer-api

ENTRYPOINT ["/bin/explorer-backend"]
EXPOSE 8080
ENTRYPOINT ["/bin/explorer-api"]

# profiling port
EXPOSE 6060

# gRPC port
EXPOSE 9990
37 changes: 37 additions & 0 deletions Dockerfile.collector
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Inspired by https://container-solutions.com/faster-builds-in-docker-with-go-1-11/
# Base build image
FROM golang:1.14.6-alpine3.12 AS build_base
RUN apk add bash make git curl unzip rsync libc6-compat gcc musl-dev
WORKDIR /go/src/github.com/spacemeshos/explorer-backend

# Force the go compiler to use modules
ENV GO111MODULE=on
ENV GOPROXY=https://proxy.golang.org

# We want to populate the module cache based on the go.{mod,sum} files.
COPY go.mod .
COPY go.sum .

# Download dependencies
RUN go mod download

RUN go get github.com/golang/[email protected]

# This image builds the explorer-backend
FROM build_base AS server_builder
# Here we copy the rest of the source code
COPY . .

# And compile the project
RUN make collector

#In this last stage, we start from a fresh Alpine image, to reduce the image size and not ship the Go compiler in our production artifacts.
FROM alpine AS explorer-collector

# Finally we copy the statically compiled Go binary.
COPY --from=server_builder /go/src/github.com/spacemeshos/explorer-backend/build/collector /bin/explorer-collector

ENTRYPOINT ["/bin/explorer-collector"]

# profiling port
EXPOSE 6060
42 changes: 42 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
VERSION := 0.1.0
COMMIT = $(shell git rev-parse HEAD)
SHA = $(shell git rev-parse --short HEAD)
CURR_DIR = $(shell pwd)
CURR_DIR_WIN = $(shell cd)
BIN_DIR = $(CURR_DIR)/build
BIN_DIR_WIN = $(CURR_DIR_WIN)/build
export GO111MODULE = on

BRANCH := $(shell bash -c 'if [ "$$TRAVIS_PULL_REQUEST" == "false" ]; then echo $$TRAVIS_BRANCH; else echo $$TRAVIS_PULL_REQUEST_BRANCH; fi')

# Set BRANCH when running make manually
ifeq ($(BRANCH),)
BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
endif

# Setup the -ldflags option to pass vars defined here to app vars
LDFLAGS = -ldflags "-X main.version=${VERSION} -X main.commit=${COMMIT} -X main.branch=${BRANCH}"

PKGS = $(shell go list ./...)

PLATFORMS := windows linux darwin
os = $(word 1, $@)

all:
.PHONY: all

apiserver:
ifeq ($(OS),Windows_NT)
cd cmd/apiserver ; go build -o $(BIN_DIR_WIN)/apiserver.exe; cd ..
else
cd cmd/apiserver ; go build -o $(BIN_DIR)/apiserver; cd ..
endif
.PHONY: apiserver

collector:
ifeq ($(OS),Windows_NT)
cd cmd/collector ; go build -o $(BIN_DIR_WIN)/collector.exe; cd ..
else
cd cmd/collector ; go build -o $(BIN_DIR)/collector; cd ..
endif
.PHONY: collector
1 change: 1 addition & 0 deletions api/httpserver/.#httpserver.go
76 changes: 38 additions & 38 deletions api/httpserver/httpserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,44 +85,44 @@ func New(ctx context.Context, cfg *Config, storage *storage.Storage) (*Server, e

http.Handle("/", server.router)

epochsRouter := server.router.PathPrefix("/epochs").Subrouter()
epochsRouter.HandleFunc("/", server.restService.EpochsHandler).Methods("GET")
epochsRouter.HandleFunc("/{id:[0-9]+}", server.restService.EpochHandler).Methods("GET")
epochsRouter.HandleFunc("/{id:[0-9]+}/layers", server.restService.EpochLayersHandler).Methods("GET")
epochsRouter.HandleFunc("/{id:[0-9]+}/txs", server.restService.EpochTxsHandler).Methods("GET")
epochsRouter.HandleFunc("/{id:[0-9]+}/smeshers", server.restService.EpochSmeshersHandler).Methods("GET")
epochsRouter.HandleFunc("/{id:[0-9]+}/rewards", server.restService.EpochRewardsHandler).Methods("GET")
epochsRouter.HandleFunc("/{id:[0-9]+}/atxs", server.restService.EpochAtxsHandler).Methods("GET")


layersRouter := server.router.PathPrefix("/layers").Subrouter()
layersRouter.HandleFunc("/", server.restService.LayersHandler).Methods("GET")
layersRouter.HandleFunc("/{id:[0-9]+}", server.restService.LayerHandler).Methods("GET")
layersRouter.HandleFunc("/{id:[0-9]+}/txs", server.restService.LayerTxsHandler).Methods("GET")
layersRouter.HandleFunc("/{id:[0-9]+}/smeshers", server.restService.LayerSmeshersHandler).Methods("GET")
layersRouter.HandleFunc("/{id:[0-9]+}/blocks", server.restService.LayerBlocksHandler).Methods("GET")
layersRouter.HandleFunc("/{id:[0-9]+}/rewards", server.restService.LayerRewardsHandler).Methods("GET")
layersRouter.HandleFunc("/{id:[0-9]+}/atxs", server.restService.LayerAtxsHandler).Methods("GET")

server.router.HandleFunc("/smeshers", server.restService.SmeshersHandler).Methods("GET")
server.router.HandleFunc("/smeshers/{id}", server.restService.SmesherHandler).Methods("GET")
server.router.HandleFunc("/smeshers/{id}/atxs", server.restService.SmesherAtxsHandler).Methods("GET")
server.router.HandleFunc("/smeshers/{id}/rewards", server.restService.SmesherRewardsHandler).Methods("GET")

server.router.HandleFunc("/apps", server.restService.NotImplemented).Methods("GET")
server.router.HandleFunc("/apps/{id}", server.restService.NotImplemented).Methods("GET")

server.router.HandleFunc("/txs", server.restService.TransactionsHandler).Methods("GET")
server.router.HandleFunc("/txs/{id}", server.restService.TransactionHandler).Methods("GET")

server.router.HandleFunc("/rewards", server.restService.RewardsHandler).Methods("GET")
server.router.HandleFunc("/rewards/{id}", server.restService.RewardHandler).Methods("GET")

server.router.HandleFunc("/address/{id}", server.restService.AccountsHandler).Methods("GET")
server.router.HandleFunc("/address/{id}/txs", server.restService.AccountHandler).Methods("GET")
server.router.HandleFunc("/address/{id}/rewards", server.restService.AccountRewardsHandler).Methods("GET")

server.router.HandleFunc("/blocks/{id}", server.restService.BlocksHandler).Methods("GET")
server.router.HandleFunc("/network-info", server.restService.NetworkInfoHandler).Methods("GET")

server.router.HandleFunc("/epochs", server.restService.EpochsHandler).Methods("GET")
server.router.HandleFunc("/epochs/{id:[0-9]+}", server.restService.EpochHandler).Methods("GET")
server.router.HandleFunc("/epochs/{id:[0-9]+}/layers", server.restService.EpochLayersHandler).Methods("GET")
server.router.HandleFunc("/epochs/{id:[0-9]+}/txs", server.restService.EpochTxsHandler).Methods("GET")
server.router.HandleFunc("/epochs/{id:[0-9]+}/smeshers", server.restService.EpochSmeshersHandler).Methods("GET")
server.router.HandleFunc("/epochs/{id:[0-9]+}/rewards", server.restService.EpochRewardsHandler).Methods("GET")
server.router.HandleFunc("/epochs/{id:[0-9]+}/atxs", server.restService.EpochAtxsHandler).Methods("GET")

server.router.HandleFunc("/layers", server.restService.LayersHandler).Methods("GET")
server.router.HandleFunc("/layers/{id:[0-9]+}", server.restService.LayerHandler).Methods("GET")
server.router.HandleFunc("/layers/{id:[0-9]+}/txs", server.restService.LayerTxsHandler).Methods("GET")
server.router.HandleFunc("/layers/{id:[0-9]+}/smeshers", server.restService.LayerSmeshersHandler).Methods("GET")
server.router.HandleFunc("/layers/{id:[0-9]+}/blocks", server.restService.LayerBlocksHandler).Methods("GET")
server.router.HandleFunc("/layers/{id:[0-9]+}/rewards", server.restService.LayerRewardsHandler).Methods("GET")
server.router.HandleFunc("/layers/{id:[0-9]+}/atxs", server.restService.LayerAtxsHandler).Methods("GET")

server.router.HandleFunc("/smeshers", server.restService.SmeshersHandler).Methods("GET")
server.router.HandleFunc("/smeshers/{id}", server.restService.SmesherHandler).Methods("GET")
server.router.HandleFunc("/smeshers/{id}/atxs", server.restService.SmesherAtxsHandler).Methods("GET")
server.router.HandleFunc("/smeshers/{id}/rewards", server.restService.SmesherRewardsHandler).Methods("GET")

server.router.HandleFunc("/apps", server.restService.NotImplemented).Methods("GET")
server.router.HandleFunc("/apps/{id}", server.restService.NotImplemented).Methods("GET")

server.router.HandleFunc("/txs", server.restService.TransactionsHandler).Methods("GET")
server.router.HandleFunc("/txs/{id}", server.restService.TransactionHandler).Methods("GET")

server.router.HandleFunc("/rewards", server.restService.RewardsHandler).Methods("GET")
server.router.HandleFunc("/rewards/{id}", server.restService.RewardHandler).Methods("GET")

server.router.HandleFunc("/address", server.restService.AccountsHandler).Methods("GET")
server.router.HandleFunc("/address/{id}", server.restService.AccountHandler).Methods("GET")
server.router.HandleFunc("/address/{id}/txs", server.restService.AccountTransactionsHandler).Methods("GET")
server.router.HandleFunc("/address/{id}/rewards", server.restService.AccountRewardsHandler).Methods("GET")

server.router.HandleFunc("/blocks/{id}", server.restService.BlocksHandler).Methods("GET")

log.Info("HTTP server is created")
return server, nil
Expand Down
85 changes: 62 additions & 23 deletions api/httpserver/rest/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,18 @@ func (s *Service) AccountsHandler(w http.ResponseWriter, r *http.Request) {

filter := &bson.D{}

total, err := s.storage.GetAccountsCount(s.ctx, filter)
if err != nil {
}
buf.WriteByte('{')

data, err := s.storage.GetAccounts(s.ctx, filter, options.Find().SetSort(bson.D{{"address", 1}}).SetLimit(pageSize).SetSkip((pageNumber - 1) * pageSize).SetProjection(bson.D{{"_id", 0}}))
if err != nil {
total := s.storage.GetAccountsCount(s.ctx, filter)
if total > 0 {
data, err := s.storage.GetAccounts(s.ctx, filter, options.Find().SetSort(bson.D{{"address", 1}}).SetLimit(pageSize).SetSkip((pageNumber - 1) * pageSize).SetProjection(bson.D{{"_id", 0}}))
if err != nil {
}
setDataInfo(buf, data)
} else {
setDataInfo(buf, nil)
}

buf.WriteByte('{')

setDataInfo(buf, data)
buf.WriteByte(',')

header := Header{}
Expand Down Expand Up @@ -61,17 +62,18 @@ func (s *Service) AccountHandler(w http.ResponseWriter, r *http.Request) {
}
filter := &bson.D{{"address", id}}

total, err := s.storage.GetAccountsCount(s.ctx, filter)
if err != nil {
}
buf.WriteByte('{')

data, err := s.storage.GetAccounts(s.ctx, filter, options.Find().SetSort(bson.D{{"address", 1}}).SetLimit(pageSize).SetSkip((pageNumber - 1) * pageSize).SetProjection(bson.D{{"_id", 0}}))
if err != nil {
total := s.storage.GetAccountsCount(s.ctx, filter)
if total > 0 {
data, err := s.storage.GetAccounts(s.ctx, filter, options.Find().SetSort(bson.D{{"address", 1}}).SetLimit(pageSize).SetSkip((pageNumber - 1) * pageSize).SetProjection(bson.D{{"_id", 0}}))
if err != nil {
}
setDataInfo(buf, data)
} else {
setDataInfo(buf, nil)
}

buf.WriteByte('{')

setDataInfo(buf, data)
buf.WriteByte(',')

header := Header{}
Expand All @@ -96,23 +98,60 @@ func (s *Service) AccountRewardsHandler(w http.ResponseWriter, r *http.Request)

vars := mux.Vars(r)
idStr := vars["id"]
id, err := strconv.Atoi(idStr)
if err != nil {
return nil, http.StatusBadRequest, fmt.Errorf("Failed to process parameter 'id' invalid number: reqID %v, id %v, error %v", reqID, idStr, err)

filter := &bson.D{{"coinbase", idStr}}

buf.WriteByte('{')

total := s.storage.GetRewardsCount(s.ctx, filter)
if total > 0 {
data, err := s.storage.GetRewards(s.ctx, filter, options.Find().SetSort(bson.D{{"coinbase", 1}}).SetLimit(pageSize).SetSkip((pageNumber - 1) * pageSize).SetProjection(bson.D{{"_id", 0}}))
if err != nil {
}
setDataInfo(buf, data)
} else {
setDataInfo(buf, nil)
}
filter := &bson.D{{"coinbase", id}}

total, err := s.storage.GetRewardsCount(s.ctx, filter)
buf.WriteByte(',')

header := Header{}
header["Content-Type"] = "application/json"

err = setPaginationInfo(buf, total, pageNumber, pageSize)
if err != nil {
}

data, err := s.storage.GetRewards(s.ctx, filter, options.Find().SetSort(bson.D{{"coinbase", 1}}).SetLimit(pageSize).SetSkip((pageNumber - 1) * pageSize).SetProjection(bson.D{{"_id", 0}}))
buf.WriteByte('}')

return header, http.StatusOK, nil
})
}

func (s *Service) AccountTransactionsHandler(w http.ResponseWriter, r *http.Request) {
_ = s.process("GET", w, r, func(reqID uint64, requestBuf []byte, buf *bytes.Buffer) (Header, int, error) {

pageNumber, pageSize, err := getPaginationInfo(r)
if err != nil {
}

vars := mux.Vars(r)
idStr := vars["id"]

filter := &bson.D{{"sender", idStr}}

buf.WriteByte('{')

setDataInfo(buf, data)
total := s.storage.GetTransactionsCount(s.ctx, filter)
if total > 0 {
data, err := s.storage.GetTransactions(s.ctx, filter, options.Find().SetSort(bson.D{{"counter", 1}}).SetLimit(pageSize).SetSkip((pageNumber - 1) * pageSize).SetProjection(bson.D{{"_id", 0}}))
if err != nil {
}
setDataInfo(buf, data)
} else {
setDataInfo(buf, nil)
}

buf.WriteByte(',')

header := Header{}
Expand Down
17 changes: 9 additions & 8 deletions api/httpserver/rest/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@ func (s *Service) BlocksHandler(w http.ResponseWriter, r *http.Request) {

filter := &bson.D{}

total, err := s.storage.GetBlocksCount(s.ctx, filter)
if err != nil {
}
buf.WriteByte('{')

data, err := s.storage.GetBlocks(s.ctx, filter, options.Find().SetSort(bson.D{{"id", 1}}).SetLimit(pageSize).SetSkip((pageNumber - 1) * pageSize).SetProjection(bson.D{{"_id", 0}}))
if err != nil {
total := s.storage.GetBlocksCount(s.ctx, filter)
if total > 0 {
data, err := s.storage.GetBlocks(s.ctx, filter, options.Find().SetSort(bson.D{{"id", 1}}).SetLimit(pageSize).SetSkip((pageNumber - 1) * pageSize).SetProjection(bson.D{{"_id", 0}}))
if err != nil {
}
setDataInfo(buf, data)
} else {
setDataInfo(buf, nil)
}

buf.WriteByte('{')

setDataInfo(buf, data)
buf.WriteByte(',')

header := Header{}
Expand Down
Loading

0 comments on commit 1c47e68

Please sign in to comment.