Skip to content

Commit

Permalink
feat: Generate OpenAPI spec for the REST API
Browse files Browse the repository at this point in the history
The OpenAPI spec is generated from the Sidetree model using swagger annotations.

closes #57

Signed-off-by: Bob Stasyszyn <[email protected]>
  • Loading branch information
bstasyszyn committed Oct 28, 2019
1 parent a14a3c6 commit 97a31da
Show file tree
Hide file tree
Showing 12 changed files with 175 additions and 21 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@
# OS generated files
.DS_Store

coverage.txt
coverage.txt
.build
20 changes: 19 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
GO_CMD ?= go
export GO111MODULE=on

# Controller API entry point to be used for generating Open API specifications
OPENAPI_SPEC_META=pkg/restapi/diddochandler/doc.go
OPENAPI_DOCKER_IMG=quay.io/goswagger/swagger
# TODO: Switched to dev since release version doesn't support go 1.13
OPENAPI_DOCKER_IMG_VERSION=dev

checks: license lint

license:
Expand All @@ -26,7 +32,19 @@ lint:
unit-test:
@scripts/unit.sh

all: checks unit-test
.PHONY: generate-openapi-spec
generate-openapi-spec:
@echo "Generating and validating controller API specifications using Open API"
@mkdir -p .build/rest/openapi/spec
@SPEC_META=$(OPENAPI_SPEC_META) SPEC_LOC=.build/rest/openapi/spec \
DOCKER_IMAGE=$(OPENAPI_DOCKER_IMG) DOCKER_IMAGE_VERSION=$(OPENAPI_DOCKER_IMG_VERSION) \
scripts/generate-openapi-spec.sh

.PHONY: clean
clean:
rm -rf .build

all: clean checks unit-test generate-openapi-spec



Expand Down
75 changes: 75 additions & 0 deletions pkg/restapi/diddochandler/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

// Package diddochandler DID document API.
//
//
// Terms Of Service:
//
// Schemes: http, https
// Host: 127.0.0.1:8080
// Version: 0.1.0
// License: SPDX-License-Identifier: Apache-2.0
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// swagger:meta
package diddochandler

import (
"github.com/trustbloc/sidetree-core-go/pkg/restapi/model"
)

// swagger:route POST /document create-did-document request
// Creates/updates a DID document.
// Responses:
// default: error
// 200: response

// Resolve swagger:route GET /document/{id} resolve-did-document resolveDocParams
// Resolves a DID document by ID or validates the DID document if provided.
// Responses:
// default: error
// 200: response

// Contains the DID document.
//swagger:response response
//nolint:deadcode,unused
type responseWrapper struct {
// The body of the response.
//
// required: true
// in: body
Body model.Response
}

// Contains the request.
//swagger:parameters request
//nolint:deadcode,unused
type requestWrapper struct {
// The body of the request.
//
// required: true
// in: body
Body model.Request
}

// resolveDocumentParams model
// This is used for getting specific DID document
//
//swagger:parameters resolveDocParams
//nolint:deadcode,unused
type resolveDocumentParams struct {
// The ID of the DID document or the DID document to be validated.
//
// in: path
// required: true
ID string `json:"id"`
}
5 changes: 0 additions & 5 deletions pkg/restapi/diddochandler/resolvehandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,3 @@ func (o *ResolveHandler) Method() string {
func (o *ResolveHandler) Handler() common.HTTPRequestHandler {
return o.Resolve
}

// Resolve resolves a DID document by ID or DID document
func (o *ResolveHandler) Resolve(rw http.ResponseWriter, req *http.Request) {
o.ResolveHandler.Resolve(rw, req)
}
30 changes: 26 additions & 4 deletions pkg/restapi/diddochandler/restapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"net/http"
"strings"
"testing"
"time"

"github.com/gorilla/mux"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -80,17 +81,23 @@ func httpPut(t *testing.T, url string, req *model.Request) (*model.Response, err
require.NoError(t, err)

httpReq.Header.Set("Content-Type", "application/json")

resp, err := client.Do(httpReq)
resp, err := invokeWithRetry(
func() (response *http.Response, e error) {
return client.Do(httpReq)
},
)
require.NoError(t, err)

return handleHttpResp(t, resp)
}

// httpGet send a regular GET request to the sidetree-node and expects 'side tree document' argument as a response
func httpGet(t *testing.T, url string) (*model.Response, error) {
client := &http.Client{}
resp, err := client.Get(url)
resp, err := invokeWithRetry(
func() (response *http.Response, e error) {
return client.Get(url)
},
)
require.NoError(t, err)
return handleHttpResp(t, resp)
}
Expand All @@ -114,6 +121,21 @@ func decode(t *testing.T, response *http.Response, v interface{}) {
require.NoError(t, err)
}

func invokeWithRetry(invoke func() (*http.Response, error)) (*http.Response, error) {
remainingAttempts := 20
for {
resp, err := invoke()
if err == nil {
return resp, err
}
remainingAttempts--
if remainingAttempts == 0 {
return nil, err
}
time.Sleep(100 * time.Millisecond)
}
}

type restService struct {
httpServer *http.Server
}
Expand Down
5 changes: 0 additions & 5 deletions pkg/restapi/diddochandler/updatehandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,3 @@ func (h *UpdateHandler) Method() string {
func (h *UpdateHandler) Handler() common.HTTPRequestHandler {
return h.Update
}

// Update updates/creates a DID document.
func (h *UpdateHandler) Update(rw http.ResponseWriter, req *http.Request) {
h.UpdateHandler.Update(rw, req)
}
3 changes: 3 additions & 0 deletions pkg/restapi/model/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ SPDX-License-Identifier: Apache-2.0
package model

// Error contains the error message
// swagger:response error
type Error struct {
// message
// Required: true
Message string `json:"message"`
}
13 changes: 11 additions & 2 deletions pkg/restapi/model/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,17 @@ SPDX-License-Identifier: Apache-2.0
package model

// Header is the operation header
// swagger:model Header
type Header struct {
Alg string `json:"alg"`
Kid string `json:"kid"`
// alg
// Required: true
Alg string `json:"alg"`

// kid
// Required: true
Kid string `json:"kid"`

// operation
// Required: true
Operation OperationType `json:"operation"`
}
1 change: 1 addition & 0 deletions pkg/restapi/model/operation_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ SPDX-License-Identifier: Apache-2.0
package model

// OperationType is the operation type
// swagger:model OperationType
type OperationType string

const (
Expand Down
15 changes: 12 additions & 3 deletions pkg/restapi/model/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,17 @@ SPDX-License-Identifier: Apache-2.0
package model

// Request is the document request
// swagger:model docRequest
type Request struct {
Header *Header `json:"header"`
Payload string `json:"payload"`
Signature string `json:"signature"`
// header
// Required: true
Header *Header `json:"header"`

// payload
// Required: true
Payload string `json:"payload"`

// signature
// Required: true
Signature string `json:"signature"`
}
2 changes: 2 additions & 0 deletions pkg/restapi/model/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ SPDX-License-Identifier: Apache-2.0
package model

// Response is the document response
// swagger:model docResponse
type Response struct {
// in:body
Body interface{} `json:"body,omitempty"`
}
24 changes: 24 additions & 0 deletions scripts/generate-openapi-spec.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/bash
#
# Copyright SecureKey Technologies Inc. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
set -e

CODEBASE="$(dirname "$PWD")"
SPEC_LOC="${SPEC_LOC}"
SPEC_META="${SPEC_META:-pkg/restapi/diddochandler/doc.go}"
OUTPUT="$SPEC_LOC/openAPI.yml"
IMAGE="${DOCKER_IMAGE:-quay.io/goswagger/swagger}"
IMAGE_VERSION="${DOCKER_IMAGE_VERSION:-latest}"

# generate and validate commands
GENERATE_COMMAND="generate spec $SPEC_META -o $OUTPUT"
VALIDATE_COMMAND="validate $OUTPUT"

echo "Generating Open API spec"
docker run --rm -e GOPATH=$HOME/go:/go -v $HOME:$HOME -w $(pwd) ${IMAGE}:${IMAGE_VERSION} $GENERATE_COMMAND

echo "Validating generated spec"
docker run --rm -e GOPATH=$HOME/go:/go -v $HOME:$HOME -w $(pwd) ${IMAGE}:${IMAGE_VERSION} $VALIDATE_COMMAND

0 comments on commit 97a31da

Please sign in to comment.