Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested object #116

Merged
merged 5 commits into from Jul 24, 2019
Merged

Nested object #116

merged 5 commits into from Jul 24, 2019

Conversation

BeniVF
Copy link
Contributor

@BeniVF BeniVF commented Jul 16, 2019

Objective

You can find, the objectives for all these PRs here: https://github.com/47deg/marlow/issues/188

Generating http4s client code based on a Open API specification using http4s v0.20 and 0.18 using circe to encode/decode.

Problem

Open api spec is based on Yaml/Json to define types, this means that not all the types have a name. You can inline objects if you want to. However, this can create a problematic situation when the objects are nested inside the Yaml/Json tree. Let's look at an example when Person is inline inside a Owner.

   Owner:
      required:
        - person
      properties:
        address: 
          type: string
        person:
          type: object
          required:
           - name
           - surname
          properties:
            name:
              type: string
            surname:
              type: string
            age: 
              type: integer

However, when we generate code, we can create the following situations:

final case class Owner(address: Option[String], person: final case class Person(name: String, surname: String, age: Option[Int]))

As we can see this code is not valid scala code, then we need to figure out a way to extract these nested objects from the json/yaml tree. Ideally, we should try to generate the following code:

final case class Owner(address: Option[String], person: Person)
final case class Person(name: String, surname: String, age: Option[Int])

We need to apply this solution to the schemas itself (T) and to the components, requestBody and responses in the OpenApi Tree.

Solution

In order to solve this, we have created the following entry functions to avoid the problem described above:

  • For Schemas (check outNestedObjectSpecification for more details):
def nestedTypes[T: Basis[JsonSchemaF, ?]]: T => NestedTypesState[T, T]

NestedTypesState is type used to accumulate the (String, T) we find (e.g. Person) and with a counter to avoid duplicated types (anonymous or not). At the end of the execution of NestedTypesState we should incorporate all the new schemas found into #/components/schemas.

  • For OpenApi (check out OpenApiNestedObjectSpecification for more details):
def extractNestedTypes[T: Basis[JsonSchemaF, ?]](openApi: OpenApi[T]): OpenApi[T]

Previous PRs

Copy link
Contributor

@vil1 vil1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks pretty good!
I think that traversing the tree within a State is definitely the way to go.

I think the implementation could be made more efficient by adding more information in the state though. And I also have a question about some corner cases.

Copy link
Member

@juanpedromoreno juanpedromoreno left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Member

@pepegar pepegar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thanks Beni :)

@BeniVF BeniVF merged commit fda576e into master Jul 24, 2019
@BeniVF BeniVF deleted the nested-object branch July 24, 2019 09:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants