-
Notifications
You must be signed in to change notification settings - Fork 244
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
Examples #2700
Comments
est: 13 |
Examples with the new value worldWith the introduction of the new values in TypeSpec, examples are a great fit for making use of those. Types examplesFirst and easier part is to define examples for the types. This would give parity with OpenAPI3 Decoratormodel ExampleOptions {
/** The title of the example */
title?: string;
/** Description of the example */
description?: string;
/** Scope this example can apply to */
scopes?: unknown[];
}
extern dec example(target, value: valueof unknown, options: valueof ExampleOptions); Example scopesWe could say that the title and description are good enough to be able to distinguish across version and visibility as well as some automatic filtering of non applicable properties could work. Proposing each examples can have a list of applicable scopes. It is then the job of the emitter to filter out examples that are not applicable to their scope. Potential scopes:
With this it means that the value parameter doesn't necessary needs to be a value of the target type. It could be the json serialized payload or some CSharp or TypeScript example code. Separate decorators for protocol/different targetsdec TypeSpec.Json.example(target, value: valueof unknown, options: ExampleOptions );
dec Typespec.Http.Client.TypeScript.example(target, value: valueof string, options: ExampleOptions );
dec Typespec.Http.Client.Csharp.example(target, value: valueof string, options: ExampleOptions ); ExamplesSimple model@example(#{
name: "John",
age: 12,
birthDate: plainDate.fromISO("2000-01-01")
})
model Person {
name: string;
age: int32;
birthDate: plainDate;
} Simple propertySame as above but the examples are on the properties model Person {
@example("John")
name: string;
@example(24)
age: int32;
@example(plainDate.fromISO("2000-01-01"))
birthDate: plainDate;
} Visibility example@example(#{
id: "user-123",
name: "John",
birthDate: plainDate.fromISO("2000-01-01")
}, #{scopes: #[forVisibility.is("read")]})
@example(#{
name: "John",
password: "password123!",
birthDate: plainDate.fromISO("2000-01-01")
}, #{scopes: #[forVisibility.is("create")]})
model Person {
@visibility("read") id: string;
@visibility("create") password: string;
name: string;
birthDate: plainDate;
} Visibility examplemodel Person {
@added(Version.v2) id?: string;
name: string;
birthDate: plainDate;
}
// Can be in a separate file
@@example(Person, #{
id: "user-123",
name: "John",
birthDate: plainDate.fromISO("2000-01-01")
}, #{scopes: #[fromVersioning.is(Versions.v2)]})
@@example(Person, #{
name: "John",
birthDate: plainDate.fromISO("2000-01-01")
}, #{scopes: #[fromVersioning.range(Versions.v1, Version.v2)]}) Json inline@Json.example(#{
name: "John",
age: 12,
birthDate: "2000-01-01"
})
model Person {
name: string;
age: int32;
birthDate: plainDate;
} or @Json.example("""
{
"name": "John",
"age": 12,
"birthDate": "2000-01-01"
}
""")
model Person {
name: string;
age: int32;
birthDate: plainDate;
} External fileLoad an external file. In this case we need to specify that this example is for a specific protocol scalar externalExample {
init path(path: string);
}
@Json.example(externalExample.path("person.json"))
model Person {
name: string;
age: int32;
birthDate: plainDate;
} Client ExamplesLoad an external file. In this case we need to specify that this example is for a specific protocol @Http.Client.TypeScript.example("""
const person: Person = {
name: "John",
age: 12,
birthDate: "2000-01-01"
};
""")
@Http.Client.CSharp.example("""
var person = new Person{
name = "John",
age = 12,
birthDate = new Date("2000-01-01")
};
""")
model Person {
name: string;
age: int32;
birthDate: plainDate;
} Operation examplesOperation examples can be a little more tricky because depending on the protocol you might want to see things differently. But maybe its just the job of the emitter to move things in the same place that the model was moved(e.g. body) DecoratorWe have 2 options for decorators
model ExampleOptions {
/** The title of the example */
title?: string;
/** Description of the example */
description?: string;
/** Scope this example can apply to */
scopes?: unknown[];
}
model OperationExample {
parameters?: unknown;
returns?: unknown;
}
extern dec opExample(target, value: valueof OperationExample, options: valueof ExampleOptions); Example scopesScopes would apply as well however some might be irrelevant as the operation would already for example define the visibility. ExamplesOperation with spread parameters@opExample(#{
parameters: #{
name: "John",
age: 12,
birthDate: plainDate.fromISO("2000-01-01")
},
returns: #{
name: "John",
age: 12,
birthDate: plainDate.fromISO("2000-01-01")
}
})
op createUser(...User): User; Operation with explicit body@opExample(#{
parameters: #{
user: #{
name: "John",
age: 12,
birthDate: plainDate.fromISO("2000-01-01")
}
},
returns: #{
name: "John",
age: 12,
birthDate: plainDate.fromISO("2000-01-01")
}
})
op createUser(@body user: User): User; Operation with spread body and headers@opExample(#{
parameters: #{
name: "John",
age: 12,
birthDate: plainDate.fromISO("2000-01-01"),
ifNotModified: eTag("abcdefghijklmnop")
},
})
op updateUser(...User, @header ifNotModified: eTag): void; Operation with explicit body and headers@opExample(#{
parameters: #{
user: #{
name: "John",
age: 12,
birthDate: plainDate.fromISO("2000-01-01")
},
ifNotModified: eTag("abcdefghijklmnop")
},
})
op updateUser(@body user: User, @header ifNotModified: eTag): void; External canonical examplesAbove we showed that we could have the example be loaded from an external file but that would be specific to a protocol(e.g. a json file, an xml file, some csharp code) We could imaging having a special file extension that define canonical examples with TypeSpec. This is just a concept there is a lot more to think about this
import "../scalars.tsp";
example "Example title" #{
name: "John",
age: 12,
birthDate: plainDate.fromISO("2000-01-01"),
data: customScalar.from("some data")
}
scalar customScalar {
from(value: string);
}
@example(import("./examples/person.example.tsp"))
model Person {
name: string;
age: int32;
birthDate: plainDate;
data: customScalar;
} Stage 1:
interface Example {
type: Type;
value: Value;
}
function getExample(): Example;
function toJsonExample(example: Example): unknown;
function toXmlExample(example: Example): unknown;
// http lib
function filterHttpVisibility(
example: Example,
visibility: Visibility
): Example;
// Versioning lib
function filterVersioning(example: Example, version: Version): Example; |
I have a question, as for the @opExample(#{
parameters: #{
user: #{
name: "John",
age: 12,
birthDate: plainDate.fromISO("2000-01-01")
},
ifNotModified: eTag("abcdefghijklmnop")
},
})
op updateUser(@body user: User, @header ifNotModified: eTag): void; what if the json we have in the example decorator has some missing required property? Would compile report error? |
the |
Fix #2700 Add support for `@example` and `@opExample` [Playground demo](https://cadlplayground.z22.web.core.windows.net/prs/3572/?c=aW1wb3J0ICJAdHlwZXNwZWMvaHR0cCI7Cgp1c2luZyBIdHRwOwoKQGV4YW1wbGUoI3sKICBpZDogInNvbWUiLAogIGJhcjogInRoaW5nxRBkYXRlOiB1dGNEYXRlVGltZS5mcm9tSVNPKCIyMDIwLTAxLTAxVDAwOsUDWiIpxDV1bml4xDA6xQrENnN0YW1wMzLfPcU9ZW5jb2RlZEFzUmZjNzIzMd9%2B0kFkb2I6IHBsYWluxDbUMsYodGltZW91dDogZHVyYXRpb27KK1BUMU3NJUluU2Vjb25kc9guMS41U9YyRmxvYddlMMc1fSkKbW9kZWwgRm9vIOgBlHN0cmluZzvoAZTKD%2FEBk8QV%2BQFzOwoKICBA5gFVKMgyS25vd25FxBRpbmcucuYBaSn%2FAX1lxUvuAV7Ee%2FEBSM1zInPmAQciLCBpbnQzMsRm%2BgFV2Dtm5AFF1j3vAWA7Cn0K5wFOUGV08wFObmFtZcwQ8ADRfQoKQG9wRecDIwogIOUDJiAgcGFyYW1ldGVyczrIE%2FADPcUnZXTLINQi6ACDIkZsdWZmecsY%2FwK66QK6xAF9xgnHB3JldHVyblR5cGX9AJ3Wed93y3fFbsUFI3sgdGl0bMVOaXJzdCIsIGRlc2NyaXDkAYU6ICJTaG93IGNyZWF05AR6YeQBGCIgfQopCm9wxhdlUGV0KOoBmyzEIjrkAbQpxQY7Cg%3D%3D&e=%40typespec%2Fopenapi3&options=%7B%7D) --------- Co-authored-by: Brian Terlson <[email protected]>
Implementation issue for: https://github.com/Azure/typespec-azure/issues/3540, #514. Design details are here
Update versioning decorators to accommodate 'never' for the version argument (meaning do not execute the decorator)
Add templates and decorators to OpenAPI library
@jsonExampleName
,@jsonExampleLiteral
,@jsonExampleParameters
,@jsonExampleReturnValue
decorators and associated accessors:@jsonExample
decorator and associated accessors@jsonExamplePath
and accessor in private namespace)@jsonExternalExample
decorator and associated accessorsImplement OpenAPI3 example support based on decorators
TypeSpec
Corresponding OpenAPI3
TypeSpec
Corresponding OpenAPI:
The text was updated successfully, but these errors were encountered: