guardrail-dev / guardrail-dev/guardrail

Sharing models between two OpenAPI specs

Open
#701 1 comment 0 reactions 0 assignees View on GitHub
enhancement question
Dominant language
Scala
Stars
541
Forks
138
PR merge metrics
No merged PRs in 30d

Description

## Scenario

Suppose I have two APIs, each with their own OpenAPI spec `apples.yaml` and `oranges.yaml`. They are both fed to Guardrail to generate routes and models in the same project, but using different `ScalaServer` instances with different packages (say `com.example.apples` and `com.example.oranges`).

While they are mostly unrelated APIs and deserve separate specs, they share some definitions, e.g. `Foo`. In OpenAPI, we can put those definitions in `common.yaml` and then reference them from the specs using `$ref: "common.yaml#/definitions/Foo"`.

Guardrail handles this scenario by generating both `com.example.apples.definitions.Foo` and `com.example.oranges.definitions.Foo`. This works OK-ish until you want to write some common code around `Foo`, and have to deal with both types. In reality, there should only be one `Foo` type, used by both APIs.

I haven't found a great way to deal with this, but maybe I'm missing something. What I would like is for there to be a `com.example.common.definitions.Foo` that can be referenced in either API.

## Current Workaround

Right now I'm using a separate `ScalaModels` instance to build `common.yaml`, this yields `com.example.common.definitions.Foo`. I then prevent Guardrail from generating `com.example.apples.definitions.Foo` and `com.example.oranges.definitions.Foo` by purposefully breaking the OpenAPI reference: changing `$ref: "common.yaml#/definitions/Foo"` to `$ref: "#/definitions/Foo"`. Guardrail says `Unable to find definition for Foo, just inlining` and carries on. Finally, I use an extra import on the apples/oranges `ScalaServer` to add `com.example.common.definitions._`, providing the single `Foo` definition to the APIs.

This is a bit of a hack. It requires that I do some text processing on the API specs to replace `` with `common.yaml` before the specs can be used by other OpenAPI tooling.

## Other Options

I considered generating the `apples` and `oranges` code in the same package. This would result in a single `Foo` definition I think. It's a bit messy, since they're unrelated, but more importantly, it doesn't protect against model name conflicts, for example if both APIs define a non-common `Bar` model, this won't work.

## Possible Solution?

What I really want to do is dictate that a definition should be generated in a package separate from the API routes. What if `x-jvm-package` was allowed on `definitions`? Then in `common.yaml` I could have:

```
definitions:
Foo:
x-jvm-package: com.example.common
```

And it would only be generated once. It would still be up to me to add the extra import to my `ScalaServer`s, or I suppose Guardrail could do this automatically if we wanted to get fancy.

But, I'm very open to other ideas, and also hoping that there's already a way to do this that I missed.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.