typespec
typespec copied to clipboard
Allow visibility on union members
I have a scenario where I want to allow a more free-form input for usability reasons, but the service will normalize to a consistent form so API consumers don't need to handle all the weird cases. Visibility on union members would enable this nicely:
model Item {
tags: ItemLabel;
}
union ItemLabel {
// want to allow creating labels with just a string,
// but the service will normalize to the Label[]
@visibility("create", "update")
string[];
Label[];
}
model Label {
name: string;
color: string;
}
@post op create(item: Item): void;
@get op read(): Item;
This is a quite common pattern so I think this is fairly important.
Slightly related to this, sometimes you want a field to be optional on create, and update, but it is always present in responses. For example, in the ToDo service, you may want to default the assignedTo to the creator, but always require it in all subsequent interactions (apart from update requests).
For the specific case in the repro, one possible representation would be to use shared routes/overloads and special-case the simplified/non-normalized shape of the model. This may not scale to arbitrarily complex "simplified" inputs that the service normalizes.
import "@typespec/http";
using TypeSpec.Http;
model Item {
tags: Label[];
}
model Label {
name: string;
color: string;
}
@sharedRoute
@route("/items")
@post op createByStrings(tags: string[]): void;
@sharedRoute
@route("/items")
@post op create(... Item): void;
@route("/items/{id}")
@get op read(id: int32): Item;
est: 8
Jumping on the bandwagon here: It would be great to enable visibility and related decorators on enum members as well. We are thinking of using the @invisible decorator to enable multi-protocol types (like types for GraphQL and OpenAPI) from the same TSP code.
For e.g. enum member names in GraphQL need to start with either one underscore or ascii string literals, so if we had an enum in TSP as follows:
enum Color {
"3blue",
"1red"
}
in order to make it compatible for GraphQL, the user can change it to:
enum Color {
@invsible(GraphQLVis)
"3blue",
@invisible(GraphQLVis)
"1red",
@invisible(HttpVis)
"threeBlue",
@invisible(HttpVis)
"oneRed"
}
where GraphQLVis, and HttpVis are enums on visibility. This would generate the following enum for GraphQL:
enum Color {
THREEBLUE
ONERED
}
where 3blue and 1red are invisible to GraphQL and threeBlue and oneRed are invisible to HTTP.
Adding the discord discussion for more context: https://discord.com/channels/1247582902930116749/1250119513681301514/1301208304802070621 for more context.
To help with prioritization: I just ran into this myself
I also ran into this -- found out when I tried to use @opExample and it wanted the Lifecycle.Read version of the object on an update.
Here's a playground example that shows this clearly.
https://typespec.io/playground/?c=aW1wb3J0ICJAdHlwZXNwZWMvaHR0cCI7CtIZcmVzdNUZb3BlbmFwaTMiOwoKQHNlcnZpY2UoI3sgdGl0bGU6ICJXaWRnZXQgU8YaIiB9KQpuYW1lc3BhY2UgRGVtb8caOwp1c2luZyBSZXN0yAxIdHRwyAxPcGVuQVBJOwoKbW9kZWwgxlhCYXNlIHsKICBAa2V5IGlkOiBzdHJpbmc7CiAgd2VpZ2h0OiBpbnQzMsQRY29sb3I6ICJyZWQiIHwgImJsdWUiOwp9CgplbnVtx1JLaW5kxVJIZWF2eSwKICBMxEcsxCdjb25zdCBleGFtcGxlVXBkYXRlxSbGOiA9ICPEOWtpbmQ6y04uyUpoxAlQcm9wUmVhZFdyaXTkASF3xAgiLAp9O89h01suLi7YftFg5QDpYWQixVnmATTMUmV4dGVuZHPwAUj2AL3kAT5AdmlzaWJpbGl0eShMaWZlY3ljbGUu5gCILCDKEsR8KfcA7eoBndZO1TzKN33oAMnlAZP%2FAMnwAMnFNMVEQGRpc2NyaW1pbmF0ZWQKdW5pb27HKsU7xX467AEu5AFdbMRAOsx75QIUQGVycm9y5wCYRcQMxURjb2Rl6wJ7bWVzc2Fn6wEC6QJOb3BF%2FwJQcGFyYW1ldGVyczrGESDlAukiMSLkAJcgIHfFLjr5ApgKICB9xCpyZXR1cm5UeXBlySzMJuQCJ0DEd29wIOQCOShAcGF0aOsDVCnoAU8gfOYA6TsKQOkAvij6AMgpCsRKY2jEWXXFHdFbLCBAYm9keekAy8c50nE%3D&e=%40typespec%2Fopenapi3&options=%7B%7D