Skip to content
This repository has been archived by the owner on Feb 17, 2024. It is now read-only.

Use an !include in a union #713

Open
sheamunion opened this issue Jun 25, 2019 · 6 comments
Open

Use an !include in a union #713

sheamunion opened this issue Jun 25, 2019 · 6 comments

Comments

@sheamunion
Copy link

I want to create a required, nullable property with a user-defined type in a separate file. How can I accomplish this?

Response.raml

#%RAML 1.0 DataType

type: object
properties:
  error: nil | !include Error.raml

Error.raml

#%RAML 1.0 DataType

type: object
properties:
  code: string
  message: string
@jstoiko
Copy link
Contributor

jstoiko commented Jul 23, 2019

!includes cannot participate in a union so your example is invalid.

There are several ways to achieve this depending on the structure of your RAML definition(s), one of them is to use a RAML library, e.g.:

Library.raml:

#%RAML 1.0 Library

types:
  Error: !include Error.raml
  Response:
    type: object
      properties:
        error: Error?

Error.raml:

#%RAML 1.0 DataType

type: object
properties:
  code: string
  message: string

PS: Note that error: Error? is equivalent to error: Error | nil. error: <anyTypeHere> also implies that the error property MUST be present regardless of its value. If what you intend is to make the error property optional, then you'll want to write error?: Error instead.

@GauthierPLM
Copy link

I also miss the possibility to do an include in an Union, especially when building datatypes where a value must be either another datatype or nil.

Either this could be managed by accepting nil | !include Type.raml or a nullable property added to the field, similar to the requiredproperty.

@jstoiko
Copy link
Contributor

jstoiko commented Jul 24, 2020

I don't see much of a limitation here since any type can be first defined (in that case by !includeing) it and later re-used in an union. Also, nullable can be expressed either using the | nil syntax of the ? (trailing question mark) syntax.

@GauthierPLM
Copy link

May I ask how would you do this so currency can be null or the type Currency?

#%RAML 1.0 DataType
type: object
additionalProperties: false
properties:
  id: integer
  entityId: integer
  entityName: string
  managingEntityId: integer?
  currencyCode: string
  currency: any # !include Currency.raml | nil

@jstoiko
Copy link
Contributor

jstoiko commented Jul 24, 2020

You can either turn your fragment into a RAML Library:

#%RAML 1.0 Library
types:
  Currency:
  MyType:
    type: object
    additionalProperties: false
    properties:
      id: integer
      entityId: integer
      entityName:
      managingEntityId: integer?
      currencyCode:
      currency: Currency? # equivalent to: Currency | nil

or use an external library in which Currency type would be defined:

#%RAML 1.0 DataType

uses: 
  lib: myLibrary.raml

type: object
additionalProperties: false
properties:
  id: integer
  entityId: integer
  entityName: string
  managingEntityId: integer?
  currencyCode: string
  currency: lib.Currency? # equivalent to: lib.Currency | nil

@GauthierPLM
Copy link

GauthierPLM commented Sep 4, 2020

After your suggestions, I played a bit with my RAML definitions and used both suggestions. Here are my thoughts:

  • Declaring the type as a library (your first example) has two disadvantages:
    • If we choose to include all types in the library file, the file might become very long (Salesforce objects for example) and would break the factorisation of the definitions.
    • or we only include one type per library file, which would defeat the purpose of having both libraries and datatypes. I see libraries as a way to put together multiples types and make them easily importable. I use this to bring all files in the same folder and import them together.
  • including a library in the DataType with uses can create cyclic dependencies if the datatypes is included in the library. For example (see code below), if I have a datatype Address.raml, another datatype Customer.raml with a field of type Address, and both types are used in the library.raml file, importing the library will create a cyclic dependency as Customer.raml will be included in itself when using library.raml.

Currently, the only solution I found is to use a type any for my field instead of including the type/using a library, especially If I do not want to create multiple libraries included in each other, defining types directly in the library, or defining the type inline (defining the Address type in the address field of Customer.raml).

The solutions I can imagine are:

  • The possibility to nullify a type via an additional property nullable (similar to required). This would allow to explicitly declare a type nullable, including a type included.
  • The possibility to have a types field in a datatype definition or allow uses to import other datatypes in a datatype declaration. This would not only cover nullability, but also union of includes as the included type is imported before the type definition.
  • The possibility to have an union on the same line as an include : !include Address.raml | nil, but this might become messy, especially if multiple !include are brought together.

Here are the example types to illustrate the cyclic dependencies:

Address.raml

#%RAML 1.0 DataType
type: object
properties:
  street: string

Customer.raml

#%RAML 1.0 DataType
uses:
  library: library.raml
type: object
properties:
  name: string
  address: library.Address | nil

library.raml

#%RAML 1.0 Library
types:
  Address: !include Address.raml
  Customer: !include Customer.raml

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

No branches or pull requests

3 participants