Visibility
Visibility is a language feature that allows you to share a model between multiple operations and define in which contexts properties of the model are âvisible.â Visibility is a very powerful feature that allows you to define different âviewsâ of a model within different operations or contexts.
Note â ïž: Enum-based visibility as described in this document replaces visibility strings that you may have used
in the past. The system is backwards-compatible with visibility strings, but you should use enum-based visibility for
new specifications. String-based visibility (e.g. @visibility("create")) may be deprecated and removed in future
versions of TypeSpec.
Basic concepts
Section titled âBasic conceptsâ- Visibility applies to model properties only. It is used to determine when an emitter should include or exclude a property in a certain context.
- Visibility is defined using a visibility class. A visibility class is an
enumthat defines the visibility modifiers (or flags) that can be applied to a property. Anyenumcan serve as a visibility class. - Visibility classes have a default visibility, which is the set of visibility modifiers that are applied by default to a property if the visibility is not explicitly set.
Lifecycle visibility
Section titled âLifecycle visibilityâTypeSpec provides a built-in visibility called âresource lifecycle visibility.â This visibility allows you to declare whether properties are visible when passing a resource to or reading a resource from an API endpoint. For example:
model Example { /** * The unique identifier of this resource. * * The ID is automatically generated by the service, so it cannot be set when the resource is created or updated, * but the server will return it when the resource is read. */ @visibility(Lifecycle.Read) id: string;
/** * The name of this resource. * * The name can be set when the resource is created, but may not be changed. */ @visibility(Lifecycle.Create, Lifecycle.Read) name: string;
/** * The description of this resource. * * By default, properties are visible in all lifecycle phases, so this property * is present in all lifecycle phases. */ description: string;}In the above example, each property of the Example model has a lifecycle visibility that instructs emitters to include
or exclude the property when creating, updating, or reading the Example resource.
TypeSpecâs HTTP library, OpenAPI emitter, and other standard functionality use the Lifecycle visibility to create
different views of the Example model based on which lifecycle phase is used in a particular operation.
In the following example, the type of the input and output of each operation is affected by the lifecycle visibility
of the properties in the Example model.
@route("/example")interface Examples { /** * When an operation uses the POST verb, it uses the `Create` lifecycle visibility to determine which properties * are visible. */ @post create(@body example: Example): Created<Example> | Error;
/** * When an operation uses the GET verb, it uses the `Read` lifecycle visibility to determine which properties * are visible. */ @get read(@path id: string): Ok<Example> | Error;
/** * When an operation uses the PATCH verb, it uses the `Update` lifecycle visibility to determine which properties * are visible. */ @patch update(@path id: string, @body example: Example): Ok<Example> | Error;}The above interface generates the following OpenAPIv3 schemas:
paths: /example: post: parameters: [] responses: "200": content: application/json: schema: $ref: "#/components/schemas/Example" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/Example" /example/{id}: get: parameters: - name: id in: path required: true schema: type: string responses: "200": content: application/json: schema: $ref: "#/components/schemas/Example" patch: parameters: - name: id in: path required: true schema: type: string responses: "200": content: application/json: schema: $ref: "#/components/schemas/Example" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ExampleUpdate"components: schemas: Example: type: object required: - id - name - description properties: id: type: string readOnly: true name: type: string description: type: string ExampleUpdate: type: object properties: description: type: stringNotice:
- The
idproperty is markedreadOnly: truebecause it is only visible when reading the resource. - The
ExampleUpdateschema only includes thedescriptionproperty because it is the only property that is visible when updating the resource. - Each of the
pathsreference the correct schema based on the lifecycle phase that the operations use. - The TypeSpec model is only defined once, and any changes in the output schemas are derived from the lifecycle visibility of the properties in the model.
Lifecycle modifiers
Section titled âLifecycle modifiersâThe following visibility modifiers are available in the Lifecycle visibility class:
Create: The property is visible when the resource is created. This visibility is checked, for example, when a property is a parameter in an HTTPPOSToperation.Read: The property is visible when the resource is read. This visibility is checked, for example, when a property is returned in an HTTPGEToperation.Update: The property is visible when the resource is updated. This visibility is checked, for example, when a property is a parameter in an HTTPPATCHorPUToperation.Delete: The property is visible when a resource is deleted. This visibility is checked, for example, when a property is a parameter in an HTTPDELETEoperation.Query: The property is visible when a resource is passed as a parameter in a query. This visibility is checked, for example, when a property is a parameter in an HTTPGEToperation (this should not be confused with an HTTP query parameter defined using@query).
Lifecycle visibility transforms
Section titled âLifecycle visibility transformsâYou can explicitly compute the shape of a model within a specific lifecycle phase by using the four built-in templates for lifecycle transforms:
Create<T extends Model>: creates a copy ofTwith only the properties that are visible in theCreatelifecycle phase, recursively.Read<T extends Model>: creates a copy ofTwith only the properties that are visible in theReadlifecycle phase, recursively.Update<T extends Model>: creates a copy ofTwith only the properties that are visible in theUpdatelifecycle phase, with the types of the properties set toCreateOrUpdate<T>, recursively.CreateOrUpdate<T>: creates a copy ofTwith only the properties that have either theCreateorUpdatevisibility modifiers enabled, recursively.Delete<T>: creates a copy ofTwith only the properties that have theLifecycle.Deletemodifier enabled, recursively.Query<T>: creates a copy ofTwith only the properties that have theLifecycle.Querymodifier enabled, recursively.
For example:
model Example { @visibility(Lifecycle.Create) id: string;
@visibility(Lifecycle.Create, Lifecycle.Read) name: string;
@visibility(Lifecycle.Update) description: string;}
model ReadExample is Read<Example>;
model CreateExample is Create<Example>;
model UpdateExample is Update<Example>;
model CreateOrUpdateExample is CreateOrUpdate<Example>;When you use these templates, the resulting models have no Lifecycle visibility modifiers applied, so that any
emitters or libraries that use lifecycle visibility will not alter them further.
Visibility modifiers
Section titled âVisibility modifiersâEach property has its own set of active visibility modifiers for each visibility class. The active modifiers can be changed using the decorators described in this section.
Note: Changing the visibility for one visibility class does not affect other visibility classes. If you change the
visibility for the Lifecycle visibility class, it will not affect the modifiers that are active for any other
visibility classes.
@visibility
Section titled â@visibilityâThe @visibility decorator enables visibility modifiers. It takes a list of visibility modifiers as arguments and
sets them on the property. For example:
@visibility(Lifecycle.Create, Lifecycle.Read)name: string;In this example, the name property has the Create and Read visibility modifiers enabled.
If visibility has already been set explicitly on a property, the @visibility decorator ADDS its own visibility
modifiers to the currently-active modifiers. It does not replace the existing modifiers. For example:
@visibility(Lifecycle.Create)@visibility(Lifecycle.Read)name: string;In this example, the name property has both the Create and Read visibility modifiers enabled, but not the Update
visibility modifier. The @visibility decorator starts from an empty set of modifiers and adds the Create modifier,
then adds the Read modifier.
@removeVisibility
Section titled â@removeVisibilityâThe @removeVisibility decorator disables visibility modifiers. It takes a list of visibility modifiers as arguments
and removes them from the property. For example:
@removeVisibility(Lifecycle.Update)name: string;This use of @removeVisibility is equivalent to the above examples with the @visibility decorator, but it uses the @removeVisibility
decorator to remove the Update visibility modifier from the name property rather than adding the Create and Read
visibility modifiers. The @removeVisibility decorator starts from the default set of visibility modifiers and removes
the Update modifier.
If the visibility has already been set on a property, the @removeVisibility decorator removes its visibility from
the currently-active modifiers. It does not replace the existing modifiers. For example:
@removeVisibility(Lifecycle.Update)@removeVisibility(Lifecycle.Create)id: string;In this example, the id property has the Update and Create visibility modifiers removed, but it retains the Read
visibility modifier.
@invisible
Section titled â@invisibleâThe @invisible decorator disables all visibility modifiers on a property within a given visibility class. For example:
@invisible(Lifecycle)invisible: string;In this example, the invisible property has no visibility modifiers enabled in the Lifecycle visibility class.
Visibility filters
Section titled âVisibility filtersâThe @withVisibilityFilter decorator allows you to transform a model by applying a visibility filter to it. A
visibility filter is an object that defines constraints on which visibility modifiers must be enabled/disabled for a
property to be visible. For example:
model Example { @visibility(Lifecycle.Create) id: string;
@visibility(Lifecycle.Create, Lifecycle.Read) name: string;
@visibility(Lifecycle.Update) description: string;}
@withVisibilityFilter(#{ all: [Lifecycle.Create, Lifecycle.Read] })model CreateAndReadExample { ...Example;}
@withVisibilityFilter(#{ any: [Lifecycle.Create, Lifecycle.Update] })model CreateOrUpdateExample { ...Example;}
@withVisibilityFilter(#{ none: [Lifecycle.Update] })model NonUpdateExample { ...Example;}In the above example, the CreateAndReadExample model is a copy of the Example model with only the the properties
that have BOTH the Create and Read visibility modifiers enabled (i.e. only the name property). The
CreateOrUpdateExample model is a copy of the Example model with only the properties that have EITHER the Create
or Update visibility modifiers enabled (i.e. the id and name properties). The NonUpdateExample model is a copy
of the Example model with only the properties that do not have the Update visibility modifier enabled (i.e. the
id and name properties).
Note: For Lifecycle visibility, you should ordinarily use the Create, Read, Update, and CreateOrUpdate
templates instead of @withVisibilityFilter directly, but you can use @withVisibilityFilter to create custom âviewsâ
of a model that use visibility classes other than Lifecycle or custom filter logic.
Visibility classes
Section titled âVisibility classesâAny TypeSpec enum can serve as a visibility class. The members of the enum define the visibility modifiers in the
class. For example, the following is the definition of the Lifecycle visibility class defined in the TypeSpec standard
library:
enum Lifecycle { Create, Read, Update,}This visibility class defines three visibility modifiers: Create, Read, and Update. By default, all properties
have ALL three visibilities in the Lifecycle enum enabled.
Setting default visibility
Section titled âSetting default visibilityâYou can set the default visibility for a visibility class by declaring it on the enum using the @defaultVisibility
decorator:
@defaultVisibility(Example.A)enum Example { A, B,}In this example, any property that does not declare an Example visibility modifier will have the A visibility by
default.
Note: While you can define your own visibility classes, emitters will not recognize them unless they have been
programmed to do so. You can leverage custom visibility classes in your own emitters, but they will have no effect on
the standard emitters unless those emitters choose to adopt and recognize those visibility classes as meaningful. The
Lifecycle visibility class is a standard visibility class that is recognized by several emitters. You can, however,
use your own visibility classes with the built in @withVisibilityFilter decorator to transform your models in whatever
ways you see fit.