github.com/snyk/vervet/v6@v6.2.4/README.md (about) 1 # vervet 2 3 Vervet is an HTTP API version lifecycle management tool, allowing APIs to be designed, developed, versioned and released from [resources](https://github.com/snyk/sweater-comb/blob/main/docs/principles/api_program.md#resources) independently and concurrently. 4 5 In a large organization, there might be many teams involved in delivering a large API -- such as at [Snyk](https://snyk.io) where Vervet was developed. 6 7 Within a single small team, there is still often a need to simultaneously try new things in parts of an API while maintaining stability. 8 9 While Vervet was developed in the context of a RESTful API, Vervet can be used with any HTTP API expressed in OpenAPI 3 -- even if it does not adhere to strict REST principles. 10 11 ### [API Versioning](https://github.com/snyk/sweater-comb/blob/main/docs/principles/version.md) 12 13 To summarize the API versioning supported by Vervet: 14 15 #### What is versioned? 16 17 Resource versions are defined in OpenAPI 3, as if each resource were a standalone service. 18 19 #### How are resource version specs organized? 20 21 Resources are organized in a standard directory structure by release date, using OpenAPI extensions to define lifecycle concepts like stability. 22 23 #### How does versioning work? 24 25 - Resources are versioned independently by date and stability, with a well-defined deprecation and sunsetting policy. 26 - Additive, non-breaking changes can be made to released versions. Breaking changes trigger a new version. 27 - New versions deprecate and sunset prior versions, on a timeline determined by the stability level. 28 29 [Read more about API versioning](https://github.com/snyk/sweater-comb/blob/main/docs/principles/version.md). 30 31 ## Features 32 33 A brief tour of Vervet's features. 34 35 ### Building a service OpenAPI from resources 36 37 Vervet collects the OpenAPI specification of each resource version and merges them into a series of OpenAPI specifications that describe the entire application, at each distinct release version in its underlying parts. 38 39 Given a directory structure of resource versions, each defined by an OpenAPI specification as if it were an independent service: 40 41 tree resources 42 43 ``` 44 resources 45 ├── _examples 46 │ └── hello-world 47 │ ├── 2021-06-01 48 │ │ └── spec.yaml 49 │ ├── 2021-06-07 50 │ │ └── spec.yaml 51 │ └── 2021-06-13 52 │ └── spec.yaml 53 └── projects 54 └── 2021-06-04 55 └── spec.yaml 56 ``` 57 58 and a Vervet project configuration that instructs how to put them together: 59 60 cat .vervet.yaml 61 62 ```yaml 63 apis: 64 my-api: 65 resources: 66 - path: "resources" 67 output: 68 path: "versions" 69 ``` 70 71 `vervet build` aggregates these resources' individual OpenAPI specifications to describe the entire service API _at each distinct version date and stability level_ from its component parts. 72 73 tree versions 74 75 ``` 76 versions/ 77 ├── 2021-06-01 78 │ ├── spec.json 79 │ └── spec.yaml 80 ├── 2021-06-01~beta 81 │ ├── spec.json 82 │ └── spec.yaml 83 ├── 2021-06-01~experimental 84 │ ├── spec.json 85 │ └── spec.yaml 86 ├── 2021-06-04 87 │ ├── spec.json 88 │ └── spec.yaml 89 ├── 2021-06-04~beta 90 │ ├── spec.json 91 │ └── spec.yaml 92 ├── 2021-06-04~experimental 93 │ ├── spec.json 94 │ └── spec.yaml 95 ├── 2021-06-07 96 │ ├── spec.json 97 │ └── spec.yaml 98 ├── 2021-06-07~beta 99 │ ├── spec.json 100 │ └── spec.yaml 101 ├── 2021-06-07~experimental 102 │ ├── spec.json 103 │ └── spec.yaml 104 ├── 2021-06-13 105 │ ├── spec.json 106 │ └── spec.yaml 107 ├── 2021-06-13~beta 108 │ ├── spec.json 109 │ └── spec.yaml 110 └── 2021-06-13~experimental 111 ├── spec.json 112 └── spec.yaml 113 ``` 114 115 ### Code generation 116 117 Since Vervet models the composition, construction and versioning of an API, it is well positioned to coordinate code and artifact generation through the use of templates. 118 119 Generators may be defined in a YAML file, such as `generators.yaml`: 120 121 ```yaml 122 generators: 123 version-readme: 124 scope: version 125 filename: "{{ .Path }}/README" 126 template: "{{ .Here }}/templates/README.tmpl" # Located relative to the location of generators.yaml 127 ``` 128 129 The context of `README.tmpl` has full access to the resource version metadata and OpenAPI document object model. 130 131 ```yaml 132 Generated by vervet. DO NOT EDIT! 133 134 # My API 135 136 Files in this directory were generated by `@snyk/vervet` 137 for resource `{{ .ResourceVersion.Name }}` at version `{{ .ResourceVersion.Version.String }}`. 138 ``` 139 140 In a project with a `.vervet.yaml` configuration, execute the generators with 141 142 vervet generate -g generators.yaml 143 144 The simple generator above produces a README in each resource version directory. 145 146 tree resources 147 148 ``` 149 resources 150 └── thing 151 └── 2021-10-21 152 ├── README 153 └── spec.yaml 154 ``` 155 156 Generators are defined using [Go templates](https://pkg.go.dev/text/template). 157 158 Template syntax may also be used to express a directory structure of many files. A more advanced example, an Express controller generated from each operation in a resource version OpenAPI spec: 159 160 ```yaml 161 generators: 162 version-controller: 163 scope: version 164 # `files:` generates a collection of files -- which itself is expressed as a 165 # YAML template. Keys in this YAML are the paths of the files to generate, 166 # whose values are the file contents. 167 files: |- 168 {{- $path := .Path -}} 169 {{- $resource := .ResourceVersion -}} 170 {{- $version := .ResourceVersion.Version -}} 171 {{- range $path, $pathItem := .ResourceVersion.Document.Paths -}} 172 {{- range $method, $operation := $pathItem -}} 173 {{- $operationId := $operation.operationId -}} 174 {{/* Construct a context object using the 'map' function */}} 175 {{- $ctx := map "Context" . "OperationId" $operationId }} 176 {{ $path }}/{{ $operationId }}.ts: |- 177 {{/* 178 Evaluate the template by including it with the necessary context. 179 The generator's template (controller.ts.tmpl) is included as 180 "contents" from within the `files:` template. 181 */}} 182 {{ include "contents" $ctx | indent 2 }} 183 {{ end }} 184 {{- end -}} 185 template: "{{ .Here }}/templates/controller.ts.tmpl" 186 ``` 187 188 In this case, a template is being applied per `operationId` in the `spec.yaml` generated in the prior step. `version-controller` produces a collection of files, a controller module per resource, per version, per operation. 189 190 Finally, a note on scoping. Generators can be scoped to either a `version` or a `resource`. 191 192 `scope: version` generator templates execute with [VersionScope](https://pkg.go.dev/github.com/snyk/vervet/v6/internal/generator#VersionScope). This maps 1:1 with a single resource version OpenAPI specification. 193 194 `scope: resource` generator templates execute with [ResourceScope](https://pkg.go.dev/github.com/snyk/vervet/v6/internal/generator#ResourceScope). This is a collection of resource versions, useful for building resource routers. 195 196 ## Installation 197 198 ### NPM 199 200 Within a project: 201 202 npm install @snyk/vervet 203 204 Or installed globally: 205 206 npm install -g @snyk/vervet 207 208 NPM packaging adapted from https://github.com/manifoldco/torus-cli. 209 210 ### Go 211 212 Go >= 1.16 required. 213 214 go install github.com/snyk/vervet/v6/cmd/vervet@latest 215 216 Building from source locally: 217 218 go build ./cmd/vervet 219 220 or 221 222 make build 223 224 ## Development 225 226 Vervet uses a reference set of OpenAPI documents in `testdata/resources` in 227 tests. CLI tests compare runtime compiled output with pre-compiled, expected 228 output in `testdata/output` to detect regressions. 229 230 When introducing changes that intentionally change the content of compiled 231 output: 232 233 - Run `go generate ./testdata` to update the contents of `testdata/output` 234 - Verify that the compiled output is correct 235 - Commit the changes to `testdata/output` in your proposed branch 236 237 ## Releasing a new version 238 239 A new version of `vervet` will automatically be generated for Github and `npm` when new features 240 are introduced, i.e. when commits are merged that are marked with `feat:`. 241 242 ## Deprecating a version 243 After removing the endpoint version code and specs, you may see this issue: 244 ``` 245 ENOENT: no such file or directory, open '.../spec.yaml' 246 ``` 247 To solve this: 248 1. Temporarily ignore the endpoint version code in `.vervet.yaml` 249 2. Remove the endpoint versions from `catalog-info.yaml` 250 3. Remove the old OpenAPI specs. 251 252 [Example PR](https://github.com/snyk/registry/pull/33489/files)