{"id":19478104,"url":"https://github.com/snyk/vervet","last_synced_at":"2025-04-09T14:12:05.616Z","repository":{"id":37057797,"uuid":"379722737","full_name":"snyk/vervet","owner":"snyk","description":"API resource versioning tool","archived":false,"fork":false,"pushed_at":"2024-10-18T20:57:21.000Z","size":1931,"stargazers_count":18,"open_issues_count":24,"forks_count":5,"subscribers_count":67,"default_branch":"main","last_synced_at":"2024-10-19T12:53:13.886Z","etag":null,"topics":["api","code-generation","compiler","versioning"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/snyk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-23T20:32:59.000Z","updated_at":"2024-10-18T20:49:40.000Z","dependencies_parsed_at":"2024-02-19T09:50:28.212Z","dependency_job_id":"fe58adfd-09f5-4307-ab79-6ac8e0f9627e","html_url":"https://github.com/snyk/vervet","commit_stats":{"total_commits":331,"total_committers":32,"mean_commits":10.34375,"dds":0.5679758308157099,"last_synced_commit":"de78f1d82a72c79dc22f751fe06e0150d9232acd"},"previous_names":[],"tags_count":207,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snyk%2Fvervet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snyk%2Fvervet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snyk%2Fvervet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snyk%2Fvervet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/snyk","download_url":"https://codeload.github.com/snyk/vervet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248054196,"owners_count":21039952,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","code-generation","compiler","versioning"],"created_at":"2024-11-10T19:47:08.639Z","updated_at":"2025-04-09T14:12:05.570Z","avatar_url":"https://github.com/snyk.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Vervet\n\nVervet 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.\n\nIn 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.\n\nWithin a single small team, there is still often a need to simultaneously try new things in parts of an API while maintaining stability.\n\nWhile 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.\n\n### [API Versioning](https://github.com/snyk/sweater-comb/blob/main/docs/principles/version.md)\n\nTo summarize the API versioning supported by Vervet:\n\n#### What is versioned?\n\nResource versions are defined in OpenAPI 3, as if each resource were a standalone service.\n\n#### How are resource version specs organized?\n\nResources are organized in a standard directory structure by release date, using OpenAPI extensions to define lifecycle concepts like stability.\n\n#### How does versioning work?\n\n- Resources are versioned independently by date and stability, with a well-defined deprecation and sunsetting policy.\n- Additive, non-breaking changes can be made to released versions. Breaking changes trigger a new version.\n- New versions deprecate and sunset prior versions, on a timeline determined by the stability level.\n\n[Read more about API versioning](https://github.com/snyk/sweater-comb/blob/main/docs/principles/version.md).\n\n## Features\n\nA brief tour of Vervet's features.\n\n### Building a service OpenAPI from resources\n\nVervet 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.\n\nGiven a directory structure of resource versions, each defined by an OpenAPI specification as if it were an independent service:\n\n    tree resources\n\n```\nresources\n├── _examples\n│   └── hello-world\n│       ├── 2021-06-01\n│       │   └── spec.yaml\n│       ├── 2021-06-07\n│       │   └── spec.yaml\n│       └── 2021-06-13\n│           └── spec.yaml\n└── projects\n    └── 2021-06-04\n        └── spec.yaml\n```\n\nand a Vervet project configuration that instructs how to put them together:\n\n    cat .vervet.yaml\n\n```yaml\napis:\n  my-api:\n    resources:\n      - path: \"resources\"\n    output:\n      path: \"versions\"\n```\n\n`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.\n\n    tree versions\n\n```\nversions/\n├── 2021-06-01\n│   ├── spec.json\n│   └── spec.yaml\n├── 2021-06-01~beta\n│   ├── spec.json\n│   └── spec.yaml\n├── 2021-06-01~experimental\n│   ├── spec.json\n│   └── spec.yaml\n├── 2021-06-04\n│   ├── spec.json\n│   └── spec.yaml\n├── 2021-06-04~beta\n│   ├── spec.json\n│   └── spec.yaml\n├── 2021-06-04~experimental\n│   ├── spec.json\n│   └── spec.yaml\n├── 2021-06-07\n│   ├── spec.json\n│   └── spec.yaml\n├── 2021-06-07~beta\n│   ├── spec.json\n│   └── spec.yaml\n├── 2021-06-07~experimental\n│   ├── spec.json\n│   └── spec.yaml\n├── 2021-06-13\n│   ├── spec.json\n│   └── spec.yaml\n├── 2021-06-13~beta\n│   ├── spec.json\n│   └── spec.yaml\n└── 2021-06-13~experimental\n    ├── spec.json\n    └── spec.yaml\n```\n\n### Simplified Versioning (from 2024-10-15)\n\nFrom 2024-10-15, Vervet introduced a new \"simplified versioning\" scheme.\n\nThe main differences introduced by simplified versioning are:\n\n- **Stability dropped from the spec level to the individual path level**: Each API path can now be labeled as either `beta` or `GA` (general availability). The `experimental` stability level has been removed. This means that paths within the same version of the spec can have different stability statuses, allowing for greater flexibility and precision.\n\n- **No changes required from developers defining APIs**: Developers still define their APIs in the same way as before, and Vervet handles the collation and versioning of specs in the new format automatically. The way specs are defined, updated, and maintained remains familiar, ensuring a smooth transition.\n\n- **End-user API requests are simplified**: API consumers no longer need to specify the stability when calling a particular version. They can simply provide the date of the version they want, and Vervet will resolve whether each path is `GA` or `beta`. If a path has been promoted to `GA`, subsequent versions cannot publish it as `beta` again.\n\nThis change is aimed at simplifying how users interact with versioned APIs while maintaining clear definitions and stabilities at the path level.\n\n#### Examples for Simplified Versioning\n\nTo illustrate how simplified versioning works in practice, let’s consider some examples:\n\n##### Example 1: Requesting a Version without Specifying Stability\n\nConsider an API with paths `/pets` and `/owners`. Suppose the `/pets` path is `GA` and the `/owners` path is `beta` as of version date `2024-10-20`.\n\n- **Request:**\n\n  ```\n  GET /api/2024-10-20/pets\n  ```\n\n  - **Response:** This request will be handled by the GA version of `/pets`.\n\n- **Request:**\n  ```\n  GET /api/2024-10-20/owners\n  ```\n  - **Response:** This request will be handled by the beta version of `/owners`.\n\nThe user does not need to specify the stability explicitly. Vervet determines the appropriate path stability (`GA` or `beta`) automatically.\n\n##### Example 2: Path Promotion to GA\n\nLet’s say that as of `2024-11-10`, the `/owners` path is promoted to `GA`.\n\n- **Request:**\n  ```\n  GET /api/2024-11-15/owners\n  ```\n  - **Response:** The request will be handled by the GA version of `/owners`.\n\nOnce a path is promoted to GA, any subsequent version cannot publish it as `beta` again. Therefore, users can be confident that they are always accessing a stable version of a path if it is marked as GA.\n\n##### Example 3: Multiple Paths with Mixed Stability\n\nConsider an API version dated `2024-12-01` with the following paths:\n\n- `/pets`: GA\n- `/owners`: GA\n- `/appointments`: beta\n\n- **Request:**\n\n  ```\n  GET /api/2024-12-01/appointments\n  ```\n\n  - **Response:** The request will be handled by the beta version of `/appointments`.\n\n- **Request:**\n  ```\n  GET /api/2024-12-01/pets\n  ```\n  - **Response:** The request will be handled by the GA version of `/pets`.\n\nThis approach allows different parts of an API to evolve at different paces, providing flexibility for developers and a clearer experience for end-users.\n\n## Code generation\n\nSince 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.\n\nGenerators may be defined in a YAML file, such as `generators.yaml`:\n\n```yaml\ngenerators:\n  version-readme:\n    scope: version\n    filename: \"{{ .Path }}/README\"\n    template: \"{{ .Here }}/templates/README.tmpl\" # Located relative to the location of generators.yaml\n```\n\nThe context of `README.tmpl` has full access to the resource version metadata and OpenAPI document object model.\n\n```yaml\nGenerated by vervet. DO NOT EDIT!\n\n# My API\n\nFiles in this directory were generated by `@snyk/vervet`\nfor resource `{{ .ResourceVersion.Name }}` at version `{{ .ResourceVersion.Version.String }}`.\n```\n\nIn a project with a `.vervet.yaml` configuration, execute the generators with\n\n    vervet generate -g generators.yaml\n\nThe simple generator above produces a README in each resource version directory.\n\n    tree resources\n\n```\nresources\n└── thing\n    └── 2021-10-21\n        ├── README\n        └── spec.yaml\n```\n\nGenerators are defined using [Go templates](https://pkg.go.dev/text/template).\n\nTemplate 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:\n\n```yaml\ngenerators:\n  version-controller:\n    scope: version\n    # `files:` generates a collection of files -- which itself is expressed as a\n    # YAML template.  Keys in this YAML are the paths of the files to generate,\n    # whose values are the file contents.\n    files: |-\n      {{- $path := .Path -}}\n      {{- $resource := .ResourceVersion -}}\n      {{- $version := .ResourceVersion.Version -}}\n      {{- range $path, $pathItem := .ResourceVersion.Document.Paths -}}\n      {{- range $method, $operation := $pathItem -}}\n      {{- $operationId := $operation.operationId -}}\n      {{/* Construct a context object using the 'map' function */}}\n      {{- $ctx := map \"Context\" . \"OperationId\" $operationId }}\n      {{ $path }}/{{ $operationId }}.ts: |-\n        {{/*\n             Evaluate the template by including it with the necessary context.\n             The generator's template (controller.ts.tmpl) is included as\n             \"contents\" from within the `files:` template.\n           */}}\n        {{ include \"contents\" $ctx | indent 2 }}\n      {{ end }}\n      {{- end -}}\n    template: \"{{ .Here }}/templates/controller.ts.tmpl\"\n```\n\nIn 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.\n\nFinally, a note on scoping. Generators can be scoped to either a `version` or a `resource`.\n\n`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.\n\n`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.\n\n## Installation\n\n### NPM\n\nWithin a project:\n\n    npm install @snyk/vervet\n\nOr installed globally:\n\n    npm install -g @snyk/vervet\n\nNPM packaging adapted from https://github.com/manifoldco/torus-cli.\n\n### Go\n\nGo \u003e= 1.16 required.\n\n    go install github.com/snyk/vervet/v6/cmd/vervet@latest\n\nBuilding from source locally:\n\n    go build ./cmd/vervet\n\nor\n\n    make build\n\n## Development\n\nVervet uses a reference set of OpenAPI documents in `testdata/resources` in\ntests. CLI tests compare runtime compiled output with pre-compiled, expected\noutput in `testdata/output` to detect regressions.\n\nWhen introducing changes that intentionally change the content of compiled\noutput:\n\n- Run `go generate ./testdata` to update the contents of `testdata/output`\n- Verify that the compiled output is correct\n- Commit the changes to `testdata/output` in your proposed branch\n\n## Releasing a new version\n\nA new version of `vervet` will automatically be generated for Github and `npm` when new features\nare introduced, i.e. when commits are merged that are marked with `feat:`.\n\n## Deprecating a version\n\nAfter removing the endpoint version code and specs, you may see this issue:\n\n```\nENOENT: no such file or directory, open '.../spec.yaml'\n```\n\nTo solve this:\n\n1. Temporarily ignore the endpoint version code in `.vervet.yaml`\n2. Remove the endpoint versions from `catalog-info.yaml`\n3. Remove the old OpenAPI specs.\n\n[Example PR](https://github.com/snyk/registry/pull/33489/files)\n\n# Vervet Underground\n\n# What Vervet Underground does and why\n\nIn order to understand _why_ Vervet Underground exists and the problem it solves, you should first become familiar with the [API versioning scheme](https://github.com/snyk/sweater-comb/blob/main/docs/principles/version.md) that Vervet supports. The main idea is, an API may be authored in parts, each of those parts may be versioned, and all the distinct versions are assembled to produce a cohesive timeline of versions for the entire service.\n\nJust as Vervet compiles a timeline of OpenAPI versions for a single service from independently versioned parts, Vervet Underground (VU) compiles a timeline of OpenAPI spec versions for a SaaS from independently versioned microservices, each of which contributes parts of the SaaS API.\n\n# Service API aggregation by example\n\n## The pet store gets microservices\n\nTo illustrate how this works in practice, let's deconstruct a pet store into two services:\n\n- `petfood.default.svc.cluster.local`, which knows about pet food.\n- `animals.default.svc.cluster.local`, which knows about animals.\n\nFor sake of example, let's assume the following versions are published by each service:\n\npetfood has:\n\n- `2021-07-04~experimental`\n- `2021-08-09~beta`\n- `2021-08-09~experimental` (beta released, with some parts still experimental, so both are published)\n- `2021-09-14` . (first GA)\n- `2021-09-14~beta`\n- `2021-09-14~experimental`\n\nanimals has:\n\n- `2021-09-10~experimental`\n- `2021-10-04~experimental`\n- `2021-10-12~beta`\n- `2021-10-12~experimental`\n- `2021-11-05`\n- `2021-11-05~beta`\n- `2021-11-05~experimental`\n\nAnd, the OpenAPI spec for each version is available at `/openapi`. `/openapi` provides a JSON array of OpenAPI versions supported by the service, and `/openapi/{version}` fetches the OpenAPI spec for that particular `{version}`. For example, `GET http://petfood.default.svc.cluster.local/openapi/2021-09-14~experimental`.\n\nThere is some nuance to this to be aware of. You'll notice that some dates have multiple versions with different stabilities. This can happen because on that date, there is more than one API version available at different stability levels.\n\nThere are also some assumptions. These services are cooperatively contributing to the public pet store SaaS API. They cannot conflict with each other -- no overwriting each other's OpenAPI components, or publishing conflicting paths.\n\n## Pet store's public API\n\nFrom these service versions, what versions of the pet store API are published to the public SaaS consumer? Well, the union of all of them! So we should be able to enumerate these versions from the public SaaS API:\n\n```\nGET https://api.petstore.example.com/openapi\n\n200 OK\nContent-Type: application/json\n[\n  `2021-07-04~experimental`,   // Contains only petfood so far...\n  `2021-08-09~experimental`,\n  `2021-08-09~beta`,\n  `2021-09-10~beta`            // Petfood only (no beta version of animals yet...)\n  `2021-09-10~experimental`,   // First animals (experimental version) + petfood\n  `2021-09-14`,                // Petfood GA only, animals isn't GA yet\n  `2021-09-14~beta`,\n  `2021-09-14~experimental`,\n  `2021-10-04`,\n  `2021-10-04~beta`,\n  `2021-10-04~experimental`,\n  `2021-10-12`,\n  `2021-10-12~beta`,\n  `2021-10-12~experimental`,\n  `2021-11-05`,                // First GA release of animals, also has petfood GA (from most recent 2021-09-14)\n  `2021-11-05~beta`,\n  `2021-11-05~experimental`,\n]\n```\n\n## Past API releases can change\n\nThe examples so far have been kept simple by assuming released API versions do not change. In practice, non-breaking changes are allowed to be made to existing versions of the API at any time. [Non-breaking changes](https://github.com/snyk/sweater-comb/blob/main/docs/principles/version.md#breaking-changes) must be additive and optional. It is fine to add new HTTP methods, endpoints, request parameters or response fields, so long that the added parameters or fields are not _required_ -- which existing generated client code would have no way of knowing about.\n\nWith VU, we should be able to request a version of the public SaaS API _as it was on a given date_, regardless of the version release date.\n\n### Tracking a non-breaking change by example\n\nLet's assume that on 2021-11-08, the petfood service team adds a PATCH method to all their resources, to allow existing orders to be modified before they ship. It's a reasonable thing to do -- a new HTTP method doesn't break existing behavior! The team adds this method to every active (non-sunset) version retroactively -- why not? it was essentially the same backend code to implement it!\n\nVervet Underground not only compiles the initially published APIs from component services, it tracks changes in these APIs and updates its SaaS-level view of the API accordingly. So, VU scrapes the /openapi endpoints of its services periodically and detects the API changes on 2021-11-08, even though no new API was explicitly released that day, and now represents it as a new \"discovered\" version:\n\n```\nGET https://api.petstore.example.com/openapi\n\n200 OK\nContent-Type: application/json\n[\n  `2021-07-04~experimental`,\n  ...\n  `2021-11-05`,\n  `2021-11-05~beta`,\n  `2021-11-05~experimental`,\n  `2021-11-08`,                // A wild new version appears!\n  `2021-11-08~beta`,\n  `2021-11-08~experimental`,\n]\n```\n\n## How VU tracks non-breaking changes (even our versions have versions!)\n\nVU scrapes the `/openapi` endpoints of each service and tracks the changes in each version found. This may be stored in a directory structure, such as:\n\n```\nservices/petfood\n├── 2021-09-14~experimental\n│   ├── 2021-09-14_11_23_24.spec.yaml\n│   └── 2021-11-08_13_14_15.spec.yaml\n...\n```\n\nwhere the scraped OpenAPI is compared against the most recent last snapshot: if they differ, a new snapshot is taken.\n\nWhen the new `2021-11-08` snapshot is detected, this triggers a rebuild of the top-level SaaS OpenAPI specs with that new version added. The arrow of time eventually flows only one way and storage is cheap, so it's assumed that the compiled OpenAPI specs will be statically compiled up-front as service API changes are detected.\n\nThis snapshot version should not be taken to represent a breaking-change release, which has different deprecation and sunsetting implications. It is only used to represent what the API looked like at a given point in time.\n\n### What this means from a public API perspective\n\nIf a version date prior to `2021-11-08` resolves to `2021-09-14~experimental`, you should see the `2021-09-14~experimental` contributions to the API _as it would have appeared at that time_, in other words, you should see a view based on the `2021-07-04_11_23_24.spec.yaml` snapshot of `2021-09-14~experimental`.\n\nIf a version date after `2021-11-08` matches `2021-09-14~experimental`, let's say a request for `2021-12-10~experimental`, then you should see it as it would appear after the non-breaking change, `2021-11-08_13_14_15.spec.yaml`.\n\n# Roadmap\n\n## Minimum Viable\n\nVU aggregates OpenAPI specs from multiple services and serves them up in a single place for:\n\n- Docs\n  - Docs will likely either render public `/openapi` directly client-side or periodically scrape \u0026 update\n- Routing public v3 `/openapi` to VU's aggregated OpenAPI versions\n- Add Akamai configuration to serve the blockstored specs initially for `/openapi`\n  - Formal frontend presentation will be later\n\nThis unblocks docs for multi-service decomp.\n\n### Details\n\n- Could use block storage with a history of changes per service per version\n- Static config that tells VU where to scrape upstream OpenAPI from services (registry and friends)\n- Cron job to periodically scrape and update\n  - Or we can try to make this push and set up a webhook...\n\n##### Simplified Versioning Integration\n\nFrom 2024-10-15, Vervet Underground also integrates the simplified versioning model. With simplified versioning:\n\n- API versions compiled by VU no longer require consumers to specify the stability level (`beta`, `GA`) in the request. Instead, consumers simply request a version by date, and the paths within that version automatically resolve to their correct stability levels (`beta` or `GA`).\n- Experimental stabilities are no longer supported; all paths are now either `beta` or `GA`.\n- Changes to a path's stability are reflected by date, ensuring consistent access to `GA` or `beta` versions without ambiguity.\n\nThis results in a more straightforward API usage for clients, as they no longer need to be concerned with explicitly requesting stabilities, which reduces friction and simplifies interaction with the aggregated service APIs.\n\n##### Example: Pre and Post Pivot Date Behavior\n\nTo better understand how simplified versioning works in comparison to the previous versioning model, let’s consider an example both before and after the pivot date of `2024-10-15`.\n\n###### Pre Pivot Date Example (before 2024-10-15)\n\nConsider a pet store API with services for `animals` and `petfood`. Assume the following versions:\n\n- `animals` has:\n\n  - `2024-10-01~beta`\n  - `2024-10-01~experimental`\n\n- `petfood` has:\n  - `2024-09-20~GA`\n  - `2024-10-01~beta`\n\nIf a client requested:\n\n- **Request:**\n\n  ```\n  GET /api/2024-10-01~beta/animals\n  ```\n\n  - **Response:** This request would be served by the beta version of `/animals`.\n\n- **Request:**\n\n  ```\n  GET /api/2024-10-01~experimental/animals\n  ```\n\n  - **Response:** This request would be served by the experimental version of `/animals`.\n\n- **Request:**\n  ```\n  GET /api/2024-09-20~GA/petfood\n  ```\n  - **Response:** This request would be served by the GA version of `/petfood`.\n\nHere, users must explicitly specify the stability (`~beta`, `~experimental`, or `~GA`), which adds complexity to the request.\n\n###### Post Pivot Date Example (after 2024-10-15)\n\nAfter the pivot date of `2024-10-15`, the simplified versioning model takes effect, where all paths are collated into a single spec with individual stabilities (`beta` or `GA`). Consider the following scenario:\n\n- `animals` has:\n\n  - Path `/animals` marked as `beta` on `2024-10-20`.\n\n- `petfood` has:\n  - Path `/petfood` marked as `GA` on `2024-10-20`.\n\nIf a client requested:\n\n- **Request:**\n\n  ```\n  GET /api/2024-10-20/animals\n  ```\n\n  - **Response:** This request will be handled by the beta version of `/animals` without specifying the stability explicitly.\n\n- **Request:**\n  ```\n  GET /api/2024-10-20/petfood\n  ```\n  - **Response:** This request will be handled by the GA version of `/petfood`.\n\nWith the simplified model, clients simply provide the date, and VU handles the rest, resolving the correct stability for each path automatically.\n\nFrom 2024-10-15, Vervet Underground also integrates the simplified versioning model. With simplified versioning:\n\n- API versions compiled by VU no longer require consumers to specify the stability level (`beta`, `GA`) in the request. Instead, consumers simply request a version by date, and the paths within that version automatically resolve to their correct stability levels (`beta` or `GA`).\n- Experimental stabilities are no longer supported; all paths are now either `beta` or `GA`.\n- Changes to a path's stability are reflected by date, ensuring consistent access to `GA` or `beta` versions without ambiguity.\n\nThis results in a more straightforward API usage for clients, as they no longer need to be concerned with explicitly requesting stabilities, which reduces friction and simplifies interaction with the aggregated service APIs.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnyk%2Fvervet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsnyk%2Fvervet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnyk%2Fvervet/lists"}