Skip to content

Commit

Permalink
Serve openapi spec (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
vterdunov authored Aug 27, 2018
1 parent 128a187 commit b48177a
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 2 deletions.
4 changes: 2 additions & 2 deletions build/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ RUN make compile

FROM scratch

ARG PORT=8080
ENV PORT=${PORT}
ENV PORT=8080

CMD ["/janna-api"]

COPY api/openapi.json /janna-api/api/openapi.json
COPY --from=build-stage /go/src/github.com/vterdunov/janna-api/janna-api /janna-api
7 changes: 7 additions & 0 deletions internal/endpoint/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ type Endpoints struct {
RoleListEndpoint endpoint.Endpoint

TaskInfoEndpoint endpoint.Endpoint

OpenAPIEndpoint endpoint.Endpoint
}

// New returns an Endpoints struct where each endpoint invokes
Expand Down Expand Up @@ -83,6 +85,9 @@ func New(s service.Service, logger log.Logger) Endpoints {
taskInfoEndpoint := MakeTaskInfoEndpoint(s)
taskInfoEndpoint = LoggingMiddleware(log.With(logger, "endpoint", "TaskInfoEndpoint"))(taskInfoEndpoint)

openAPIEndpoint := MakeOpenAPIEndpoint(s)
openAPIEndpoint = LoggingMiddleware(log.With(logger, "endpoint", "OpenAPIEndpoint"))(openAPIEndpoint)

return Endpoints{
InfoEndpoint: infoEndpoint,

Expand All @@ -107,6 +112,8 @@ func New(s service.Service, logger log.Logger) Endpoints {
RoleListEndpoint: roleListEndpoint,

TaskInfoEndpoint: taskInfoEndpoint,

OpenAPIEndpoint: openAPIEndpoint,
}
}

Expand Down
31 changes: 31 additions & 0 deletions internal/endpoint/open_api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package endpoint

import (
"context"

"github.com/go-kit/kit/endpoint"
"github.com/vterdunov/janna-api/internal/service"
)

// MakeOpenAPIEndpoint returns an endpoint via the passed service
func MakeOpenAPIEndpoint(s service.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
spec, err := s.OpenAPI(ctx)
if err != nil {
return OpenAPIResponse{Spec: nil, Err: err}, err
}

return OpenAPIResponse{Spec: spec}, nil
}
}

// OpenAPIResponse serves OpenAPI specification
type OpenAPIResponse struct {
Spec []byte
Err error `json:"error,omitempty"`
}

// Failed implements Failer
func (r OpenAPIResponse) Failed() error {
return r.Err
}
8 changes: 8 additions & 0 deletions internal/service/instrumenting_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,11 @@ func (mw instrumentingMiddleware) RoleList(ctx context.Context) (_ []types.Role,
}(time.Now())
return mw.Service.RoleList(ctx)
}

func (mw instrumentingMiddleware) OpenAPI(ctx context.Context) (_ []byte, err error) {
defer func(begin time.Time) {
lvs := []string{"method", "OpenAPI", "success", fmt.Sprint(err == nil)}
mw.duration.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
return mw.Service.OpenAPI(ctx)
}
13 changes: 13 additions & 0 deletions internal/service/logging_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,16 @@ func (s *loggingMiddleware) RoleList(ctx context.Context) (_ []types.Role, err e

return s.Service.RoleList(ctx)
}

func (s *loggingMiddleware) OpenAPI(ctx context.Context) (_ []byte, err error) {
reqID := ctx.Value(http.ContextKeyRequestXRequestID)
defer func() {
s.logger.Log(
"request_id", reqID,
"method", "OpenAPI",
"err", err,
)
}()

return s.Service.OpenAPI(ctx)
}
12 changes: 12 additions & 0 deletions internal/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package service
import (
"context"
"fmt"
"io/ioutil"

"github.com/go-kit/kit/log"
"github.com/go-kit/kit/metrics"
Expand Down Expand Up @@ -69,6 +70,9 @@ type Service interface {
// TasksList(context.Context) (*status.Tasks, error)

TaskInfo(context.Context, string) (*Task, error)

// Reads Open API spec file
OpenAPI(context.Context) ([]byte, error)
}

// service implements our Service
Expand Down Expand Up @@ -257,3 +261,11 @@ func (s *service) TaskInfo(ctx context.Context, taskID string) (*Task, error) {
}
return nil, errors.New("task not found")
}

func (s *service) OpenAPI(_ context.Context) ([]byte, error) {
spec, err := ioutil.ReadFile("./api/openapi.json")
if err != nil {
return nil, err
}
return spec, err
}
29 changes: 29 additions & 0 deletions internal/transport/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ func NewHTTPHandler(endpoints endpoint.Endpoints, logger log.Logger) http.Handle
options...,
))

r.Path("/openapi").Methods("GET").Handler(httptransport.NewServer(
endpoints.OpenAPIEndpoint,
decodeOpenAPIRequest,
encodeOpenAPIResponse,
options...,
))

return r
}

Expand Down Expand Up @@ -299,6 +306,10 @@ func decodeRoleListRequest(_ context.Context, r *http.Request) (interface{}, err
return req, nil
}

func decodeOpenAPIRequest(_ context.Context, r *http.Request) (interface{}, error) {
return nil, nil
}

// common response decoder
func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
// check business logic errors
Expand All @@ -325,3 +336,21 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
"error": err.Error(),
})
}

func encodeOpenAPIResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
// check business logic errors
if e, ok := response.(endpoint.Failer); ok && e.Failed() != nil {
encodeError(ctx, e.Failed(), w)
return nil
}

w.Header().Set("Content-Type", "application/json; charset=utf-8")

res, ok := response.(endpoint.OpenAPIResponse)
if !ok {
encodeError(ctx, errors.New("could not get OpenAPI data"), w)
}

w.Write(res.Spec)
return nil
}

0 comments on commit b48177a

Please sign in to comment.