Skip to content

Commit

Permalink
Enhance OpenAPI interface, for namespace-local APIs, and extra routin…
Browse files Browse the repository at this point in the history
…g options

Signed-off-by: Peter Broadhurst <[email protected]>
  • Loading branch information
peterbroadhurst committed Sep 13, 2023
1 parent 5418e40 commit 9b71253
Show file tree
Hide file tree
Showing 61 changed files with 437 additions and 426 deletions.
5 changes: 4 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ linters-settings:
revive:
rules:
- name: unused-parameter
disabled: true
disabled: true
gosec:
excludes:
- G601 # Appears not to handle taking an address of a sub-structure, within a pointer to a structure within a loop. Which is valid and safe.
goheader:
values:
regexp:
Expand Down
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"mytag",
"NATS",
"nextpins",
"openapi",
"opid",
"optype",
"opupdate",
Expand Down
1 change: 1 addition & 0 deletions docs/reference/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ nav_order: 2
|Key|Description|Type|Default Value|
|---|-----------|----|-------------|
|defaultFilterLimit|The maximum number of rows to return if no limit is specified on an API request|`int`|`25`
|dynamicPublicURLHeader|Dynamic header that informs the backend the base public URL for the request, in order to build URL links in OpenAPI/SwaggerUI|`string`|`<nil>`
|maxFilterLimit|The largest value of `limit` that an HTTP client can specify in a request|`int`|`1000`
|passthroughHeaders|A list of HTTP request headers to pass through to dependency microservices|`[]string`|`[]`
|requestMaxTimeout|The maximum amount of time that an HTTP client can specify in a `Request-Timeout` header to keep a specific request open|[`time.Duration`](https://pkg.go.dev/time#Duration)|`10m`
Expand Down
4 changes: 2 additions & 2 deletions docs/swagger/swagger.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
components: {}
info:
title: FireFly
title: Hyperledger FireFly
version: "1.0"
openapi: 3.0.2
paths:
Expand Down Expand Up @@ -42702,4 +42702,4 @@ paths:
tags:
- Global
servers:
- url: http://localhost:5000
- url: http://localhost:5000/api/v1
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ require (
github.com/golang-migrate/migrate/v4 v4.15.2
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.5.0
github.com/hyperledger/firefly-common v1.2.19
github.com/hyperledger/firefly-common v1.3.1-0.20230912221149-2b028031e84a
github.com/hyperledger/firefly-signer v1.1.8
github.com/jarcoal/httpmock v1.2.0
github.com/lib/pq v1.10.7
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -676,8 +676,8 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hyperledger/firefly-common v1.2.19 h1:o5eZKVTFEl+o9uVxCTPdaSGxZ0VtzKtgEW0UcQXmELs=
github.com/hyperledger/firefly-common v1.2.19/go.mod h1:17lOH4YufiPy82LpKm8fPa/YXJ0pUyq01zK1CmklJwM=
github.com/hyperledger/firefly-common v1.3.1-0.20230912221149-2b028031e84a h1:8p7OEhIo+nsWkM27zrTF6cQo4nSGbtMfwwgVijwMCag=
github.com/hyperledger/firefly-common v1.3.1-0.20230912221149-2b028031e84a/go.mod h1:17lOH4YufiPy82LpKm8fPa/YXJ0pUyq01zK1CmklJwM=
github.com/hyperledger/firefly-signer v1.1.8 h1:XyJjZXesih2dWYG31m5ZYt4irH7/PdkRutMPld7AqKE=
github.com/hyperledger/firefly-signer v1.1.8/go.mod h1:vNbbROziwqkOmO0b+9ky3devjcFg0JIkR2M1KG7seTQ=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
Expand Down
28 changes: 10 additions & 18 deletions internal/apiserver/ffi2swagger.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2022 Kaleido, Inc.
// Copyright © 2023 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
Expand Down Expand Up @@ -35,7 +35,7 @@ import (
)

type FFISwaggerGen interface {
Generate(ctx context.Context, baseURL string, api *core.ContractAPI, ffi *fftypes.FFI) *openapi3.T
Build(ctx context.Context, api *core.ContractAPI, ffi *fftypes.FFI) (*ffapi.SwaggerGenOptions, []*ffapi.Route)
}

type ContractListenerInput struct {
Expand All @@ -49,15 +49,9 @@ type ContractListenerInputWithLocation struct {
Location *fftypes.JSONAny `ffstruct:"ContractListener" json:"location,omitempty"`
}

// ffiSwaggerGen generates OpenAPI3 (Swagger) definitions for FFIs
type ffiSwaggerGen struct {
}

func NewFFISwaggerGen() FFISwaggerGen {
return &ffiSwaggerGen{}
}
type ffiSwaggerGen struct{}

func (og *ffiSwaggerGen) Generate(ctx context.Context, baseURL string, api *core.ContractAPI, ffi *fftypes.FFI) (swagger *openapi3.T) {
func (swg *ffiSwaggerGen) Build(ctx context.Context, api *core.ContractAPI, ffi *fftypes.FFI) (*ffapi.SwaggerGenOptions, []*ffapi.Route) {
hasLocation := !api.Location.IsNil()

routes := []*ffapi.Route{
Expand All @@ -71,22 +65,21 @@ func (og *ffiSwaggerGen) Generate(ctx context.Context, baseURL string, api *core
},
}
for _, method := range ffi.Methods {
routes = og.addMethod(ctx, routes, method, hasLocation)
routes = addFFIMethod(ctx, routes, method, hasLocation)
}
for _, event := range ffi.Events {
routes = og.addEvent(routes, event, hasLocation)
routes = addFFIEvent(ctx, routes, event, hasLocation)
}

return ffapi.NewSwaggerGen(&ffapi.Options{
return &ffapi.SwaggerGenOptions{
Title: ffi.Name,
Version: ffi.Version,
Description: ffi.Description,
BaseURL: baseURL,
DefaultRequestTimeout: config.GetDuration(coreconfig.APIRequestTimeout),
}).Generate(ctx, routes)
}, routes
}

func (og *ffiSwaggerGen) addMethod(ctx context.Context, routes []*ffapi.Route, method *fftypes.FFIMethod, hasLocation bool) []*ffapi.Route {
func addFFIMethod(ctx context.Context, routes []*ffapi.Route, method *fftypes.FFIMethod, hasLocation bool) []*ffapi.Route {
description := method.Description
if method.Details != nil && len(method.Details) > 0 {
additionalDetailsHeader := i18n.Expand(ctx, coremsgs.APISmartContractDetails)
Expand Down Expand Up @@ -121,8 +114,7 @@ func (og *ffiSwaggerGen) addMethod(ctx context.Context, routes []*ffapi.Route, m
return routes
}

func (og *ffiSwaggerGen) addEvent(routes []*ffapi.Route, event *fftypes.FFIEvent, hasLocation bool) []*ffapi.Route {
ctx := context.Background()
func addFFIEvent(ctx context.Context, routes []*ffapi.Route, event *fftypes.FFIEvent, hasLocation bool) []*ffapi.Route {
description := event.Description
if event.Details != nil && len(event.Details) > 0 {
additionalDetailsHeader := i18n.Expand(ctx, coremsgs.APISmartContractDetails)
Expand Down
11 changes: 7 additions & 4 deletions internal/apiserver/ffi2swagger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

"github.com/getkin/kin-openapi/openapi3"
"github.com/ghodss/yaml"
"github.com/hyperledger/firefly-common/pkg/ffapi"
"github.com/hyperledger/firefly-common/pkg/fftypes"
"github.com/hyperledger/firefly/pkg/core"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -114,9 +115,10 @@ func paramNames(p openapi3.Schemas) []string {
}

func TestGenerate(t *testing.T) {
g := NewFFISwaggerGen()
api := &core.ContractAPI{}
doc := g.Generate(context.Background(), "http://localhost:12345", api, testFFI())
options, routes := (&ffiSwaggerGen{}).Build(context.Background(), api, testFFI())
options.BaseURL = "http://localhost:12345"
doc := ffapi.NewSwaggerGen(options).Generate(context.Background(), routes)

b, err := yaml.Marshal(doc)
assert.NoError(t, err)
Expand Down Expand Up @@ -150,9 +152,10 @@ func TestGenerate(t *testing.T) {
}

func TestGenerateWithLocation(t *testing.T) {
g := NewFFISwaggerGen()
api := &core.ContractAPI{Location: fftypes.JSONAnyPtr(`{}`)}
doc := g.Generate(context.Background(), "http://localhost:12345", api, testFFI())
options, routes := (&ffiSwaggerGen{}).Build(context.Background(), api, testFFI())
options.BaseURL = "http://localhost:12345"
doc := ffapi.NewSwaggerGen(options).Generate(context.Background(), routes)

b, err := yaml.Marshal(doc)
assert.NoError(t, err)
Expand Down
17 changes: 11 additions & 6 deletions internal/apiserver/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const (
routeTagNonDefaultNamespace = "Non-Default Namespace"
)

var nsRoutes = []*ffapi.Route{}
var routes = append(
globalRoutes([]*ffapi.Route{
getNamespace,
Expand Down Expand Up @@ -177,14 +178,18 @@ func namespacedRoutes(routes []*ffapi.Route) []*ffapi.Route {
for i, route := range routes {
route.Tag = routeTagDefaultNamespace

routeCopy := *route
routeCopy.Name += "Namespace"
routeCopy.Path = "namespaces/{ns}/" + route.Path
routeCopy.PathParams = append(routeCopy.PathParams, &ffapi.PathParam{
routeCopy1 := *route
routeCopy1.Name += "Namespace"
routeCopy1.Path = "namespaces/{ns}/" + route.Path
routeCopy1.PathParams = append(routeCopy1.PathParams, &ffapi.PathParam{
Name: "ns", ExampleFromConf: coreconfig.NamespacesDefault, Description: coremsgs.APIParamsNamespace,
})
routeCopy.Tag = routeTagNonDefaultNamespace
newRoutes[i] = &routeCopy
routeCopy1.Tag = routeTagNonDefaultNamespace
newRoutes[i] = &routeCopy1

// Build a separate list of NS relative routes, to build a swagger limited to one namespace
routeCopy2 := *route
nsRoutes = append(nsRoutes, &routeCopy2)
}
return append(routes, newRoutes...)
}
Loading

0 comments on commit 9b71253

Please sign in to comment.