Repository: swaggest/openapi-go
Pull request #7 (2020-05-12 09:36:42)

Add helper to setup operation

codecov[bot]: # [Codecov](https://codecov.io/gh/swaggest/openapi-go/pull/7?src=pr&el=h1) Report
> Merging [#7](https://codecov.io/gh/swaggest/openapi-go/pull/7?src=pr&el=desc) into [master](https://codecov.io/gh/swaggest/openapi-go/commit/26850d08ac8d4cbe4eec77ecb1ec6fe37c32bc7b&el=desc) will **increase** coverage by `0.12%`.
> The diff coverage is `28.88%`.

[![Impacted file tree graph](https://codecov.io/gh/swaggest/openapi-go/pull/7/graphs/tree.svg?width=650&height=150&src=pr&token=3uETjeijpQ)](https://codecov.io/gh/swaggest/openapi-go/pull/7?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master       #7      +/-   ##
==========================================
+ Coverage   11.85%   11.97%   +0.12%     
==========================================
  Files           5        5              
  Lines        4074     4116      +42     
==========================================
+ Hits          483      493      +10     
- Misses       3536     3567      +31     
- Partials       55       56       +1     
```


| [Impacted Files](https://codecov.io/gh/swaggest/openapi-go/pull/7?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [openapi3/helper.go](https://codecov.io/gh/swaggest/openapi-go/pull/7/diff?src=pr&el=tree#diff-b3BlbmFwaTMvaGVscGVyLmdv) | `54.76% <28.88%> (-30.96%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/swaggest/openapi-go/pull/7?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/swaggest/openapi-go/pull/7?src=pr&el=footer). Last update [26850d0...63d2826](https://codecov.io/gh/swaggest/openapi-go/pull/7?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml
index 19ef5dd..4ff2337 100644
--- a/.github/workflows/golangci-lint.yml
+++ b/.github/workflows/golangci-lint.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
       - uses: actions/checkout@v2
       - name: golangci-lint
-        uses: golangci/golangci-lint-action@v0.1.7
+        uses: golangci/golangci-lint-action@v0.2.0
         with:
           # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
           version: v1.26
diff --git a/Makefile b/Makefile
index 40cfdcb..90dfdfa 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,9 @@
+GOLANGCI_LINT_VERSION := "v1.27.0"
+
 gen:
 	cd resources/schema/ && json-cli gen-go openapi3.json --output ../../openapi3/entities.go --package-name openapi3 --with-zero-values --fluent-setters --root-name Spec
 	gofmt -w ./openapi3/entities.go
 
 lint:
-	golangci-lint run ./...
+	@test -s $(GOPATH)/bin/golangci-lint-$(GOLANGCI_LINT_VERSION) || (curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b /tmp $(GOLANGCI_LINT_VERSION) && mv /tmp/golangci-lint $(GOPATH)/bin/golangci-lint-$(GOLANGCI_LINT_VERSION))
+	@$(GOPATH)/bin/golangci-lint-$(GOLANGCI_LINT_VERSION) run ./...
diff --git a/go.mod b/go.mod
index 5f59282..cefa517 100644
--- a/go.mod
+++ b/go.mod
@@ -5,8 +5,8 @@ go 1.13
 require (
 	github.com/stretchr/testify v1.5.1
 	github.com/swaggest/assertjson v1.0.0
-	github.com/swaggest/jsonschema-go v0.3.0
-	github.com/swaggest/refl v0.1.2
-	github.com/swaggest/swgen v0.6.22
-	gopkg.in/yaml.v2 v2.2.8
+	github.com/swaggest/jsonschema-go v0.3.2
+	github.com/swaggest/refl v0.1.3
+	github.com/swaggest/swgen v0.6.23
+	gopkg.in/yaml.v2 v2.3.0
 )
diff --git a/go.sum b/go.sum
index 496e8d3..b6c1254 100644
--- a/go.sum
+++ b/go.sum
@@ -54,17 +54,19 @@ github.com/swaggest/assertjson v1.0.0/go.mod h1:mE5ltBbrB+Ya8Xar5OMITxya76vwLZMo
 github.com/swaggest/jsonschema-go v0.2.1 h1:SVg+zXQ46w6ewR7jZDRVbpKKC+V7Y6Xn/teC2pRS2bM=
 github.com/swaggest/jsonschema-go v0.2.1/go.mod h1:QFauBdPTrU1UltwocM5FzOWnVjVVtcWkJWG3NlK9sV0=
 github.com/swaggest/jsonschema-go v0.2.4/go.mod h1:m4VV88Gbi7lCrt9ckJzigK1rMlEeFjdZUkJr1o5MnDE=
-github.com/swaggest/jsonschema-go v0.3.0 h1:QysAjTu2u05WMpkMkKzVR8QLMXYGsx6r9BCKInJ99Hk=
-github.com/swaggest/jsonschema-go v0.3.0/go.mod h1:dZ+BzW9hUiHkb/jm+gDJnS8TPqEd0BrNkUIgJrCL3t0=
+github.com/swaggest/jsonschema-go v0.3.2 h1:k0s1XsyoXyY5hDY1ZHVEig8ROZTqPnEdKK4IhQtlWSw=
+github.com/swaggest/jsonschema-go v0.3.2/go.mod h1:TrWgbug4p2ZgcxnHDz+CvYvEtJ5KckL/XOV4mSR6FGw=
 github.com/swaggest/openapi-go v0.1.3/go.mod h1:Zx4ZgJ7XvlFH9wCOHE7u8RAjLfiHAnCHeaD5kUDujVM=
 github.com/swaggest/refl v0.1.0 h1:mz3skba8ewcPmxDryM9rETv4fSuAX4GqNxTuDfPyUM0=
 github.com/swaggest/refl v0.1.0/go.mod h1:kmYWhxNEvjfRDdMRqpaR/vLULk/SotJs9HFUCIVMK8o=
 github.com/swaggest/refl v0.1.2 h1:BfxmzI4FabeaSHijDEObFB1qaDPevcDsRetAYxg30yw=
 github.com/swaggest/refl v0.1.2/go.mod h1:kmYWhxNEvjfRDdMRqpaR/vLULk/SotJs9HFUCIVMK8o=
+github.com/swaggest/refl v0.1.3 h1:cnzEBcCNhYeLPG8Yy9JQixUkxMDsF0mo0GyzblLWrjE=
+github.com/swaggest/refl v0.1.3/go.mod h1:kmYWhxNEvjfRDdMRqpaR/vLULk/SotJs9HFUCIVMK8o=
 github.com/swaggest/swgen v0.6.20 h1:mGg20AJQu18lkx5NfqCJ9rRpAZjMc4QlXVOIS3JB1Ck=
 github.com/swaggest/swgen v0.6.20/go.mod h1:ipkZNfwztgRfbOWUllLZawfmxXprT8flqNJO9XhoMwM=
-github.com/swaggest/swgen v0.6.22 h1:vSlCN58I2wLh8i9vcXB0mOkMy8dkVulkw4Rti6HI/9k=
-github.com/swaggest/swgen v0.6.22/go.mod h1:gj2yCLONy3kosKjwRtQeT5O9qqlhUvXAiDnbVwBUNFM=
+github.com/swaggest/swgen v0.6.23 h1:9COrDC1o34xJS0NeQ2js7qGfo/Rgs16xWT0pQRvGNyY=
+github.com/swaggest/swgen v0.6.23/go.mod h1:gj2yCLONy3kosKjwRtQeT5O9qqlhUvXAiDnbVwBUNFM=
 github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
 github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
 github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
@@ -110,3 +112,5 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/openapi3/helper.go b/openapi3/helper.go
index 870e5c0..a6cc97e 100644
--- a/openapi3/helper.go
+++ b/openapi3/helper.go
@@ -23,8 +23,8 @@ func (p *PathItem) WithOperation(method string, operation Operation) *PathItem {
 
 var regexFindPathParameter = regexp.MustCompile(`{([^}:]+)(:[^/]+)?(?:})`)
 
-// AddOperation validates and sets operation by path and method.
-func (s *Spec) AddOperation(method, path string, operation Operation) error {
+// SetupOperation creates operation if it is not present and applies setup functions.
+func (s *Spec) SetupOperation(method, path string, setup ...func(*Operation) error) error {
 	method = strings.ToLower(method)
 	pathParametersSubmatches := regexFindPathParameter.FindAllStringSubmatch(path, -1)
 
@@ -36,10 +36,6 @@ func (s *Spec) AddOperation(method, path string, operation Operation) error {
 	}
 
 	pathItem := s.Paths.MapOfPathItemValues[path]
-	if _, found := pathItem.MapOfOperationValues[method]; found {
-		return errors.New("operation with method and path already exists")
-	}
-
 	pathParams := map[string]bool{}
 
 	if len(pathParametersSubmatches) > 0 {
@@ -54,6 +50,15 @@ func (s *Spec) AddOperation(method, path string, operation Operation) error {
 
 	var errs []string
 
+	operation := pathItem.MapOfOperationValues[method]
+
+	for _, f := range setup {
+		err := f(&operation)
+		if err != nil {
+			return err
+		}
+	}
+
 	paramIndex := make(map[string]bool, len(operation.Parameters))
 
 	for _, p := range operation.Parameters {
@@ -90,3 +95,20 @@ func (s *Spec) AddOperation(method, path string, operation Operation) error {
 
 	return nil
 }
+
+// AddOperation validates and sets operation by path and method.
+//
+// It will fail if operation with method and path already exists.
+func (s *Spec) AddOperation(method, path string, operation Operation) error {
+	method = strings.ToLower(method)
+	pathItem := s.Paths.MapOfPathItemValues[path]
+
+	if _, found := pathItem.MapOfOperationValues[method]; found {
+		return errors.New("operation with method and path already exists")
+	}
+
+	return s.SetupOperation(method, path, func(op *Operation) error {
+		*op = operation
+		return nil
+	})
+}


Test patch:
diff --git a/openapi3/_testdata/openapi.json b/openapi3/_testdata/openapi.json
index 1ef9ebd..6fdb6e5 100644
--- a/openapi3/_testdata/openapi.json
+++ b/openapi3/_testdata/openapi.json
@@ -226,7 +226,7 @@
       "content": {
        "application/json": {
         "schema": {
-         "$ref": "#/components/schemas/Openapi3TestWeirdResp"
+         "$ref": "#/components/schemas/Openapi3TestResp"
         }
        }
       }
@@ -248,7 +248,7 @@
         "schema": {
          "type": "array",
          "items": {
-          "$ref": "#/components/schemas/Openapi3TestWeirdResp"
+          "$ref": "#/components/schemas/Openapi3TestResp"
          }
         }
        }
@@ -347,16 +347,14 @@
       "type": "object",
       "additionalProperties": {}
      },
-     "nullableWhatever": {
-      "nullable": true
-     },
+     "nullableWhatever": {},
      "parent": {
       "$ref": "#/components/schemas/Openapi3TestResp"
      },
      "recursiveArray": {
       "type": "array",
       "items": {
-       "$ref": "#/components/schemas/Openapi3TestWeirdResp"
+       "$ref": "#/components/schemas/Openapi3TestResp"
       }
      },
      "recursiveStructArray": {
@@ -377,76 +375,6 @@
     "type": "string",
     "format": "uuid",
     "example": "248df4b7-aa70-47b8-a036-33ac447e668d"
-   },
-   "Openapi3TestWeirdResp": {
-    "title": "Sample Response",
-    "type": "object",
-    "properties": {
-     "arrayOfAnything": {
-      "type": "array",
-      "items": {}
-     },
-     "customType": {
-      "$ref": "#/components/schemas/Openapi3TestISOWeek"
-     },
-     "field1": {
-      "type": "integer"
-     },
-     "field2": {
-      "type": "string"
-     },
-     "info": {
-      "required": [
-       "foo"
-      ],
-      "type": "object",
-      "properties": {
-       "bar": {
-        "type": "number",
-        "description": "This is Bar."
-       },
-       "foo": {
-        "pattern": "\\d+",
-        "type": "string"
-       }
-      }
-     },
-     "map": {
-      "type": "object",
-      "additionalProperties": {
-       "type": "integer"
-      }
-     },
-     "mapOfAnything": {
-      "type": "object",
-      "additionalProperties": {}
-     },
-     "nullableWhatever": {
-      "nullable": true
-     },
-     "parent": {
-      "$ref": "#/components/schemas/Openapi3TestResp"
-     },
-     "recursiveArray": {
-      "type": "array",
-      "items": {
-       "$ref": "#/components/schemas/Openapi3TestWeirdResp"
-      }
-     },
-     "recursiveStructArray": {
-      "type": "array",
-      "items": {
-       "$ref": "#/components/schemas/Openapi3TestResp"
-      }
-     },
-     "uuid": {
-      "$ref": "#/components/schemas/Openapi3TestUUID"
-     },
-     "whatever": {}
-    },
-    "description": "This is a sample response.",
-    "nullable": true,
-    "x-foo": "bar"
    }
   }
  }
diff --git a/openapi3/_testdata/resp_schema.json b/openapi3/_testdata/resp_schema.json
index c3f8eea..674c076 100644
--- a/openapi3/_testdata/resp_schema.json
+++ b/openapi3/_testdata/resp_schema.json
@@ -53,15 +53,13 @@
             "additionalProperties": {},
             "type": "object"
           },
-          "nullableWhatever": {
-            "type": "null"
-          },
+          "nullableWhatever": {},
           "parent": {
             "$ref": "#/components/schemas/Openapi3TestResp"
           },
           "recursiveArray": {
             "items": {
-              "$ref": "#/components/schemas/Openapi3TestWeirdResp"
+              "$ref": "#/components/schemas/Openapi3TestResp"
             },
             "type": "array"
           },
@@ -85,78 +83,6 @@
         ],
         "type": "string",
         "format": "uuid"
-      },
-      "Openapi3TestWeirdResp": {
-        "title": "Sample Response",
-        "description": "This is a sample response.",
-        "properties": {
-          "arrayOfAnything": {
-            "items": {},
-            "type": "array"
-          },
-          "customType": {
-            "$ref": "#/components/schemas/Openapi3TestISOWeek"
-          },
-          "field1": {
-            "type": "integer"
-          },
-          "field2": {
-            "type": "string"
-          },
-          "info": {
-            "required": [
-              "foo"
-            ],
-            "properties": {
-              "bar": {
-                "description": "This is Bar.",
-                "type": "number"
-              },
-              "foo": {
-                "pattern": "\\d+",
-                "type": "string"
-              }
-            },
-            "type": "object"
-          },
-          "map": {
-            "additionalProperties": {
-              "type": "integer"
-            },
-            "type": "object"
-          },
-          "mapOfAnything": {
-            "additionalProperties": {},
-            "type": "object"
-          },
-          "nullableWhatever": {
-            "type": "null"
-          },
-          "parent": {
-            "$ref": "#/components/schemas/Openapi3TestResp"
-          },
-          "recursiveArray": {
-            "items": {
-              "$ref": "#/components/schemas/Openapi3TestWeirdResp"
-            },
-            "type": "array"
-          },
-          "recursiveStructArray": {
-            "items": {
-              "$ref": "#/components/schemas/Openapi3TestResp"
-            },
-            "type": "array"
-          },
-          "uuid": {
-            "$ref": "#/components/schemas/Openapi3TestUUID"
-          },
-          "whatever": {}
-        },
-        "type": [
-          "object",
-          "null"
-        ],
-        "x-foo": "bar"
       }
     }
   }
diff --git a/openapi3/reflect_test.go b/openapi3/reflect_test.go
index 55d2245..284aab6 100644
--- a/openapi3/reflect_test.go
+++ b/openapi3/reflect_test.go
@@ -217,6 +217,9 @@ func TestReflector_SetJSONResponse(t *testing.T) {
 		Schema.ToJSONSchema(s)
 	jsb, err = json.MarshalIndent(js, "", " ")
 	require.NoError(t, err)
+
+	require.NoError(t, ioutil.WriteFile("_testdata/resp_schema_last_run.json", jsb, 0600))
+
 	expected, err = ioutil.ReadFile("_testdata/resp_schema.json")
 	require.NoError(t, err)
 	assertjson.Equal(t, expected, jsb, string(jsb))