拓冰建站拓冰建站
首页 / 资讯中心 / 正文

TypeSpec Rest 库数据类型全解:@typespec/rest 导出的数据模型与资源操作基石

TypeSpec Rest 库数据类型全解typespec/rest 导出的数据模型与资源操作基石【免费下载链接】typespec项目地址: https://gitcode.com/GitHub_Trending/ty/typespectypespec/rest 是 TypeSpec 官方 REST 库它为 REST API 定义提供了资源Resource抽象通过resource、parentResource等装饰器把模型声明为资源再用ResourceRead、ResourceCreate等接口模板自动生成 CRUD 路由。而这一切的底层都依赖库导出的十余个数据类型scalar 与 model 模板。本文以官方参考文档>scalar TypeSpec.Rest.ResourceLocationResourceLocation表示一个指向某资源的 URL通常出现在需要返回资源地址的响应中。例如CollectionWithNextLink.nextLink字段就用它表示下一页的链接。源码中它的完整声明是packages/rest/lib/rest.tspdoc(The location of an instance of {name}, Resource) Private.resourceLocation(Resource) scalar ResourceLocationResource extends {} extends url;值得注意的两点它extends url即底层继承自url标量语义上是一个 URL它是一个带模板参数的标量Resource extends {}指明该 URL 指向的具体资源类型配合私有装饰器Private.resourceLocation(Resource)在编译期记录关联的资源类型。这样当你在分页响应或其他场景使用它时工具链能够知道 URL 指向的资源种类。键收集类型KeysOf与ParentKeysOf资源模型通过key标注键属性如key id: string。KeysOf与ParentKeysOf用于动态收集这些键并把它们展开为操作参数。KeysOfResourcemodel TypeSpec.Rest.Resource.KeysOfResourceDynamically gathers keys of the model typeResource.——动态收集目标资源的全部键含父资源链上的键无自身属性Properties: None其字段完全由模板参数推导。源码实现packages/rest/lib/resource.tspdoc(Dynamically gathers keys of the model type Resource.) copyResourceKeyParameters friendlyName({name}Key, Resource) model KeysOfResource {}三个装饰器分别说明copyResourceKeyParameters核心装饰器在编译期把资源的key属性克隆为KeysOf的成员friendlyName({name}Key, Resource)让生成的模型命名为{资源名}Key例如Thing的键模型叫ThingKey注意源码中该模型没有key属性Properties 表为空字段全部来自模板展开。ParentKeysOfResourcemodel TypeSpec.Rest.Resource.ParentKeysOfResourceDynamically gathers parent keys of the model typeResource.——只收集父资源的键用于集合级操作如POST /organizations/{orgId}/users中的{orgId}。源码实现packages/rest/lib/resource.tspdoc(Dynamically gathers parent keys of the model type Resource.) copyResourceKeyParameters(parent) friendlyName({name}ParentKey, Resource) model ParentKeysOfResource {}与KeysOf的唯一区别是copyResourceKeyParameters(parent)传入了parent过滤器。在 packages/rest/src/resource.ts 的实现中filter parent时只查找资源的父资源getParentResource若有父资源才克隆其键属性不传 filter 时克隆资源自身及其所有父资源的键cloneKeyProperties会递归父链。键克隆的底层原理cloneKeyPropertiespackages/rest/src/resource.ts做这些事先递归处理父资源保证父键在子键之前通过getResourceTypeKey查找资源的键属性该函数会优先查缓存再扫描属性中的key最后回溯baseModel见 packages/rest/src/resource.ts克隆键属性时强制optional: false防止可选键变成可选的路径参数自动为克隆出的参数补上path装饰器若原键没有附加Private.resourceTypeForKeyParam记录该参数对应的资源类型供路由与文档生成使用。这正是resource(things) model Thing { key(thingId) id: string }能自动生成GET /things/{thingId}路由测试见 packages/rest/test/resource.test.ts的原因。操作参数模型ResourceParameters与ResourceCollectionParameters这两个模型是资源接口模板中参数展开的总闸它们本身 Properties 为空全部字段来自对键收集类型的展开。ResourceParametersResourcemodel TypeSpec.Rest.Resource.ResourceParametersResourceRepresents operation parameters for the resource of typeResource.——表示针对单个资源实例的操作读、改、删所需的路径参数。源码packages/rest/lib/resource.tspdoc(Represents operation parameters for resource Resource.) model ResourceParametersResource extends {} { ...KeysOfResource; }即...KeysOfResource展开出资源自身及父链上的所有键参数。因此普通资源ThingResourceParametersThing展开为thingId键子资源User父为OrganizationResourceParametersUser展开为orgId与userId两个路径参数。ResourceCollectionParametersResourcemodel TypeSpec.Rest.Resource.ResourceCollectionParametersResourceRepresents collection operation parameters for the resource of typeResource.——表示集合操作创建、列表所需的路径参数即父资源的键。源码packages/rest/lib/resource.tspdoc(Represents collection operation parameters for resource Resource.) model ResourceCollectionParametersResource extends {} { ...ParentKeysOfResource; }对无父资源的顶层资源它展开为空集合操作不需要路径参数如GET /things对有父资源的子资源它展开为父资源键如GET /organizations/{orgId}/users中的orgId。这两个参数模型在 resource.tsp 各接口模板中被大量...展开使用例如ResourceRead.get(...ResourceParametersResource)L72ResourceCreate.create(...ResourceCollectionParametersResource, ...)L168ResourceList.list(...ResourceCollectionParametersResource)L259扩展资源接口则同时展开两者如ExtensionResourceRead.get(...ResourceParametersResource, ...ResourceParametersExtension)L375资源创建模型ResourceCreateModel与ResourceCreateOrUpdateModelResourceCreateModelResourcemodel TypeSpec.Rest.Resource.ResourceCreateModelResourceResource create operation model.——创建操作使用的请求体模型Properties 为 None内容由模板推导。源码packages/rest/lib/resource.tspfriendlyName({name}Create, Resource) withVisibility(Lifecycle.Create) model ResourceCreateModelResource extends {} is DefaultKeyVisibilityResource, Lifecycle.Read;要点friendlyName({name}Create, Resource)生成的模型名为{资源名}CreatewithVisibility(Lifecycle.Create)按Create可见性过滤资源属性即创建请求体只包含创建时允许提交的字段is DefaultKeyVisibilityResource, Lifecycle.Read键属性保持Read可见性典型场景是服务端生成 id客户端创建时不提交。ResourceCreateOrUpdateModelResourcemodel TypeSpec.Rest.Resource.ResourceCreateOrUpdateModelResourceResource create or update operation model.——创建或更新patch操作共用的请求体模型。源码packages/rest/lib/resource.tspfriendlyName({name}Update, Resource) model ResourceCreateOrUpdateModelResource extends {} is OptionalPropertiesUpdateablePropertiesDefaultKeyVisibilityResource, Lifecycle.Read;三个核心组合DefaultKeyVisibilityResource, Lifecycle.Read键默认Read可见性不可由客户端修改UpdateableProperties...只保留可更新Update 可见性的属性OptionalProperties...把保留的属性全部转为可选——patch 语义下客户端可以只提交部分字段。该模型被ResourceCreateOrUpdate.createOrUpdateL141、ResourceUpdate.updateL200、SingletonResourceUpdateL344等接口的请求体使用统一了创建与更新场景的载荷结构。操作响应模型ResourceCreatedResponse、ResourceDeletedResponse与ResourceErrorResourceCreatedResponseResourcemodel TypeSpec.Rest.Resource.ResourceCreatedResponseResourceResource create operation completed successfully.——创建成功响应固定返回 HTTP 201 并把创建的资源作为响应体。属性类型说明statusCode201状态码bodyResource创建出的资源源码packages/rest/lib/resource.tspdoc(Resource create operation completed successfully.) model ResourceCreatedResponseResource { ...CreatedResponse; /** The created resource. */ bodyRoot body: Resource; }...CreatedResponse来自typespec/http定义是model CreatedResponse is Response201见 packages/http/lib/main.tsp即状态码 201bodyRoot body: Resource将资源体标记为响应体根。ResourceCreate.create、ResourceCreateOrUpdate.createOrUpdate等接口的返回类型Resource | ResourceCreatedResponseResource | Error中的成功分支即指向它。ResourceDeletedResponsemodel TypeSpec.Rest.Resource.ResourceDeletedResponseResource deleted successfully.——删除成功响应状态码固定为 200注意文档中属性名显示为_源码中它确实以_作为属性名承载状态码。源码packages/rest/lib/resource.tspdoc(Resource deleted successfully.) model ResourceDeletedResponse { doc(The status code.) statusCode _: 200; }statusCode _: 200是 TypeSpec 中表达固定状态码的标准写法statusCode标记该属性为状态码值为字面量200。该模型不携带响应体。ResourceDelete.delete(...)返回类型为ResourceDeletedResponse | ErrorL226。ResourceErrormodel TypeSpec.Rest.Resource.ResourceErrorThe default error response for resource operations.——资源操作的默认错误响应是资源接口模板中Error模板参数的常用默认选择。属性类型说明codeint32错误码messagestring错误信息源码packages/rest/lib/resource.tspdoc(The default error response for resource operations.) model ResourceError { doc(The error code.) code: int32; doc(The error message.) message: string; }注意所有资源接口模板如ResourceReadResource, Error都要求Error模板参数满足错误模型约束——接口上的Private.validateIsError(Error)internal-decorators.ts会检查它是否通过error标记否则报告resource-missing-error诊断。同理Private.validateHasKey(Resource)会检查资源是否具有key属性否则报告resource-missing-key诊断。因此实际使用时通常需要定义自己的error model Error {}测试示例见 packages/rest/test/resource.test.ts。分页响应CollectionWithNextLinkResourcemodel TypeSpec.Rest.Resource.CollectionWithNextLinkResourceStructure for a paging response usingvalueandnextLinkto represent pagination.——列表操作的统一分页响应结构是ResourceList.list()的标准返回类型。属性类型说明valueArrayElement当前页的元素集合nextLink?TypeSpec.Rest.ResourceLocation指向下一页的链接可选没有下一页时省略源码packages/rest/lib/resource.tspdoc(Paged response of {name} items, Resource) friendlyName({name}CollectionWithNextLink, Resource) model CollectionWithNextLinkResource extends {} { doc(The items on this page) pageItems value: Resource[]; doc(The link to the next page of items) nextLink nextLink?: ResourceLocationResource; }实现要点pageItems与nextLink是typespec/http提供的分页语义装饰器分别标记页内元素集合与下一页链接供 OpenAPI 等 emitter 生成标准分页描述value: Resource[]是当前页数据nextLink?: ResourceLocationResource复用前文介绍的ResourceLocation标量语义闭环friendlyName({name}CollectionWithNextLink, Resource)使生成类型名为{资源名}CollectionWithNextLink。配合ResourceList接口模板L252-L260interface ResourceListResource extends {}, Error { autoRoute doc(Lists all instances of the resource.) listsResource(Resource) list(...ResourceCollectionParametersResource): CollectionWithNextLinkResource | Error; }即可为资源自动生成集合列表 分页的路由与文档。组合实战从数据类型到完整资源接口上述数据类型并非孤立存在而是被资源接口模板按固定模式组合。以普通资源为例完整模板见 packages/rest/lib/resource.tsp// 实例级操作读/改/删 interface ResourceInstanceOperationsResource extends {}, Error extends ResourceReadResource, Error, // get(...ResourceParametersResource) ResourceUpdateResource, Error, // update(...ResourceParametersResource, properties: ...) ResourceDeleteResource, Error {} // delete(...ResourceParametersResource) // 集合级操作创建/列表 interface ResourceCollectionOperationsResource extends {}, Error extends ResourceCreateResource, Error, // create(...ResourceCollectionParametersResource, resource: ...) ResourceListResource, Error {} // list(...ResourceCollectionParametersResource) // 全量操作 interface ResourceOperationsResource extends {}, Error extends ResourceInstanceOperationsResource, Error, ResourceCollectionOperationsResource, Error {}一个最小可运行示例import typespec/rest; import typespec/http; using TypeSpec.Rest.Resource; service namespace MyService; resource(things) model Thing { key(thingId) id: string; name: string; } error model Error { code: int32; message: string; } interface Things extends ResourceOperationsThing, Error {}展开后生成的 REST 操作与 packages/rest/test/resource.test.ts 验证的路由行为一致GET /thingslist返回CollectionWithNextLinkThingPOST /thingscreate成功返回ResourceCreatedResponseThingGET /things/{thingId}getPATCH /things/{thingId}createOrUpdate/updateDELETE /things/{thingId}delete返回ResourceDeletedResponse如果Thing声明了父资源parentResource(Organization)ResourceParametersThing与ResourceCollectionParametersThing会自动把orgId注入路径/organizations/{orgId}/things/{thingId}父资源的循环引用会被checkCircularParentResource检测并报告circular-parent-resource诊断测试见 packages/rest/test/resource.test.ts。小结typespec/rest导出的数据类型形成了清晰的分层标量层ResourceLocation描述资源 URL键层KeysOf/ParentKeysOf通过copyResourceKeyParameters动态收集键参数参数层ResourceParameters/ResourceCollectionParameters把键展开为实例或集合操作的路径参数请求模型层ResourceCreateModel/ResourceCreateOrUpdateModel依据可见性生成创建、更新请求体响应模型层ResourceCreatedResponse201、ResourceDeletedResponse200、ResourceError错误体、CollectionWithNextLink分页。理解这些类型的职责与组合方式是掌握 TypeSpec 资源抽象普通资源、Singleton、扩展资源的关键。如需进一步查阅装饰器与接口模板的完整定义可继续阅读 rest-decorators.tspresource、parentResource、autoRoute等装饰器声明与 resource.tsp全部资源接口模板并参考 resource.test.ts 与 routes.test.ts 中的路由生成验证用例。【免费下载链接】typespec项目地址: https://gitcode.com/GitHub_Trending/ty/typespec创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门