Skip to content

Commit 43581cd

Browse files
docs(http): Add JSDoc for public APIs [skip chg] (#12210)
HTTP library consumers need consistent guidance across authentication, operation payloads, routing, metadata, and experimental helpers. Document the public HTTP contracts together, including scheme identifiers, request/response body classification, parameter and response metadata, diagnostics, and typekit helpers. Existing HTTP semantics and API signatures are unchanged. Consolidates [12218](#12218), [12224](#12224), [12232](#12232). Tracked in #12228.
1 parent 1ba6b9f commit 43581cd

22 files changed

Lines changed: 486 additions & 32 deletions
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: internal
3+
packages:
4+
- "@typespec/http"
5+
---
6+
7+
Document authentication alternatives, scheme configuration, and service-level security references.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: internal
3+
packages:
4+
- "@typespec/http"
5+
---
6+
7+
Document HTTP operation, parameter, response, multipart, and file payload contracts.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: internal
3+
packages:
4+
- "@typespec/http"
5+
---
6+
7+
Document experimental route producers, HTTP typekits, stream metadata, and merge-patch configuration.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: internal
3+
packages:
4+
- "@typespec/http"
5+
---
6+
7+
Document public HTTP decorator, routing, metadata, and file/part helper contracts.

‎packages/http/src/decorators.ts‎

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import { extractParamsFromPath } from "./utils.js";
6161

6262
export const namespace = "TypeSpec.Http";
6363

64+
/** {@inheritDoc HeaderDecorator} */
6465
export const $header: HeaderDecorator = (
6566
context: DecoratorContext,
6667
entity: ModelProperty,
@@ -86,14 +87,23 @@ export const $header: HeaderDecorator = (
8687
context.program.stateMap(HttpStateKeys.header).set(entity, options);
8788
};
8889

90+
/**
91+
* Reads the header's wire name and explicitly configured serialization options.
92+
* Returns `undefined` at runtime for a type without `@header`.
93+
*/
8994
export function getHeaderFieldOptions(program: Program, entity: Type): HeaderFieldOptions {
9095
return program.stateMap(HttpStateKeys.header).get(entity);
9196
}
9297

98+
/**
99+
* Reads the explicit or kebab-case default header name.
100+
* Returns `undefined` at runtime when the type is not marked `@header`.
101+
*/
93102
export function getHeaderFieldName(program: Program, entity: Type): string {
94103
return getHeaderFieldOptions(program, entity)?.name;
95104
}
96105

106+
/** Tests whether the type has been marked as an HTTP header with `@header`. */
97107
export function isHeader(program: Program, entity: Type) {
98108
return program.stateMap(HttpStateKeys.header).has(entity);
99109
}
@@ -143,6 +153,7 @@ const [getQueryOptions, setQueryOptions] = useStateMap<
143153
ModelProperty,
144154
QueryOptions & { name: string }
145155
>(HttpStateKeys.query);
156+
/** {@inheritDoc QueryDecorator} */
146157
export const $query: QueryDecorator = (
147158
context: DecoratorContext,
148159
entity: ModelProperty,
@@ -173,6 +184,10 @@ export function resolveQueryOptionsWithDefaults(
173184
};
174185
}
175186

187+
/**
188+
* Reads `@query` options, resolving the wire name and defaulting `explode` to false.
189+
* Returns `undefined` when the type is not a query parameter.
190+
*/
176191
export function getQueryParamOptions(
177192
program: Program,
178193
entity: Type,
@@ -182,10 +197,12 @@ export function getQueryParamOptions(
182197
return { type: "query", ...resolveQueryOptionsWithDefaults(userOptions) };
183198
}
184199

200+
/** Reads the query wire name, or `undefined` when `@query` has not been applied. */
185201
export function getQueryParamName(program: Program, entity: Type): string | undefined {
186202
return getQueryParamOptions(program, entity)?.name;
187203
}
188204

205+
/** Tests for explicit `@query` metadata; does not infer parameters from a URI template. */
189206
export function isQueryParam(program: Program, entity: Type) {
190207
return program.stateMap(HttpStateKeys.query).has(entity);
191208
}
@@ -194,6 +211,7 @@ const [getPathOptions, setPathOptions] = useStateMap<ModelProperty, PathOptions
194211
HttpStateKeys.path,
195212
);
196213

214+
/** {@inheritDoc PathDecorator} */
197215
export const $path: PathDecorator = (
198216
context: DecoratorContext,
199217
entity: ModelProperty,
@@ -228,6 +246,10 @@ export function resolvePathOptionsWithDefaults(
228246
};
229247
}
230248

249+
/**
250+
* Reads `@path` options with defaults: simple style, no explode, and no reserved characters.
251+
* Returns `undefined` without `@path`; URI-template inference happens during operation resolution.
252+
*/
231253
export function getPathParamOptions(
232254
program: Program,
233255
entity: Type,
@@ -237,52 +259,63 @@ export function getPathParamOptions(
237259
return { type: "path", ...resolvePathOptionsWithDefaults(userOptions) };
238260
}
239261

262+
/** Reads the path wire name, or `undefined` when `@path` has not been applied. */
240263
export function getPathParamName(program: Program, entity: Type): string | undefined {
241264
return getPathOptions(program, entity as any)?.name;
242265
}
243266

267+
/** Tests for explicit `@path` metadata; does not infer parameters from a URI template. */
244268
export function isPathParam(program: Program, entity: Type) {
245269
return program.stateMap(HttpStateKeys.path).has(entity);
246270
}
247271

272+
/** {@inheritDoc BodyDecorator} */
248273
export const $body: BodyDecorator = (context: DecoratorContext, entity: ModelProperty) => {
249274
context.program.stateSet(HttpStateKeys.body).add(entity);
250275
};
251276

277+
/** {@inheritDoc BodyRootDecorator} */
252278
export const $bodyRoot: BodyRootDecorator = (context: DecoratorContext, entity: ModelProperty) => {
253279
context.program.stateSet(HttpStateKeys.bodyRoot).add(entity);
254280
};
255281

282+
/** {@inheritDoc BodyIgnoreDecorator} */
256283
export const $bodyIgnore: BodyIgnoreDecorator = (
257284
context: DecoratorContext,
258285
entity: ModelProperty,
259286
) => {
260287
context.program.stateSet(HttpStateKeys.bodyIgnore).add(entity);
261288
};
262289

290+
/** Tests whether the property's type was selected as the complete body by `@body`. */
263291
export function isBody(program: Program, entity: Type): boolean {
264292
return program.stateSet(HttpStateKeys.body).has(entity);
265293
}
266294

295+
/** Tests whether `@bodyRoot` selects this property for body and nested metadata resolution. */
267296
export function isBodyRoot(program: Program, entity: ModelProperty): boolean {
268297
return program.stateSet(HttpStateKeys.bodyRoot).has(entity);
269298
}
270299

300+
/** Tests whether `@bodyIgnore` excludes this property from the HTTP body. */
271301
export function isBodyIgnore(program: Program, entity: ModelProperty): boolean {
272302
return program.stateSet(HttpStateKeys.bodyIgnore).has(entity);
273303
}
274304

305+
/** {@inheritDoc MultipartBodyDecorator} */
275306
export const $multipartBody: MultipartBodyDecorator = (
276307
context: DecoratorContext,
277308
entity: ModelProperty,
278309
) => {
279310
context.program.stateSet(HttpStateKeys.multipartBody).add(entity);
280311
};
281312

313+
/** Tests whether `@multipartBody` selects this property as a multipart payload. */
282314
export function isMultipartBodyProperty(program: Program, entity: Type): boolean {
283315
return program.stateSet(HttpStateKeys.multipartBody).has(entity);
284316
}
285317

318+
/** {@inheritDoc StatusCodeDecorator} */
286319
export const $statusCode: StatusCodeDecorator = (
287320
context: DecoratorContext,
288321
entity: ModelProperty,
@@ -297,21 +330,31 @@ export function setStatusCode(program: Program, entity: Model | ModelProperty, c
297330
program.stateMap(HttpStateKeys.statusCode).set(entity, codes);
298331
}
299332

333+
/** Tests whether `@statusCode` marks the property as response status metadata. */
300334
export function isStatusCode(program: Program, entity: Type) {
301335
return program.stateSet(HttpStateKeys.statusCode).has(entity);
302336
}
303337

338+
/**
339+
* Extracts status codes or inclusive ranges from a property's type and constraints.
340+
* Returns validation diagnostics alongside any successfully extracted entries.
341+
*/
304342
export function getStatusCodesWithDiagnostics(
305343
program: Program,
306344
type: ModelProperty,
307345
): [HttpStatusCodes, readonly Diagnostic[]] {
308346
return getStatusCodesFromType(program, type, type);
309347
}
310348

349+
/** Extracts status entries from a property, discarding validation diagnostics. */
311350
export function getStatusCodes(program: Program, entity: ModelProperty): HttpStatusCodes {
312351
return ignoreDiagnostics(getStatusCodesWithDiagnostics(program, entity));
313352
}
314353

354+
/**
355+
* Gets a built-in description for a status code or its HTTP status class.
356+
* Returns `undefined` for unrecognized values, including the `"*"` default response.
357+
*/
315358
// Reference: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
316359
export function getStatusCodeDescription(statusCode: number | "*" | HttpStatusCodeRange | string) {
317360
if (typeof statusCode === "object") {
@@ -389,6 +432,10 @@ function validateVerbUniqueOnNode(context: DecoratorContext, type: Operation) {
389432
return true;
390433
}
391434

435+
/**
436+
* Reads the method assigned by an HTTP verb decorator, or `undefined` when none is set.
437+
* Does not perform the body-based method inference used by operation resolution.
438+
*/
392439
export function getOperationVerb(program: Program, entity: Type): HttpVerb | undefined {
393440
return program.stateMap(HttpStateKeys.verbs).get(entity);
394441
}
@@ -399,10 +446,15 @@ function createVerbDecorator(verb: HttpVerb) {
399446
};
400447
}
401448

449+
/** {@inheritDoc GetDecorator} */
402450
export const $get: GetDecorator = createVerbDecorator("get");
451+
/** {@inheritDoc PutDecorator} */
403452
export const $put: PutDecorator = createVerbDecorator("put");
453+
/** {@inheritDoc PostDecorator} */
404454
export const $post: PostDecorator = createVerbDecorator("post");
455+
/** {@inheritDoc DeleteDecorator} */
405456
export const $delete: DeleteDecorator = createVerbDecorator("delete");
457+
/** {@inheritDoc HeadDecorator} */
406458
export const $head: HeadDecorator = createVerbDecorator("head");
407459

408460
const _patch = createVerbDecorator("patch");
@@ -448,6 +500,7 @@ function isOriginalDecoratorApplication(context: DecoratorContext, entity: Opera
448500
return true;
449501
}
450502

503+
/** {@inheritDoc PatchDecorator} */
451504
export const $patch: PatchDecorator = (
452505
context: DecoratorContext,
453506
entity: Operation,
@@ -484,9 +537,13 @@ export function getPatchOptions(program: Program, operation: Operation): PatchOp
484537

485538
const VERB_DECORATORS = [$get, $head, $post, $put, $patch, $delete];
486539

540+
/** A server endpoint declared by `@server`, including its template parameter definitions. */
487541
export interface HttpServer {
542+
/** Server URL template, with `{name}` placeholders for server parameters. */
488543
url: string;
544+
/** Human-readable endpoint description, when supplied. */
489545
description?: string;
546+
/** Declared parameter properties keyed by their template names. */
490547
parameters: Map<string, ModelProperty>;
491548
}
492549

@@ -526,10 +583,18 @@ export const $server: ServerDecorator = (
526583
servers.push({ url, description, parameters: parameterMap });
527584
};
528585

586+
/**
587+
* Reads servers declared directly on a namespace, in decorator application order.
588+
* Returns `undefined` when none are declared; does not search parent namespaces.
589+
*/
529590
export function getServers(program: Program, type: Namespace): HttpServer[] | undefined {
530591
return program.stateMap(HttpStateKeys.servers).get(type);
531592
}
532593

594+
/**
595+
* Applies `@useAuth`, interpreting unions as alternatives and tuples as combined schemes.
596+
* Reports invalid authentication definitions before recording any extracted requirements.
597+
*/
533598
export function $useAuth(
534599
context: DecoratorContext,
535600
entity: Namespace | Interface | Operation,
@@ -543,6 +608,10 @@ export function $useAuth(
543608
}
544609
}
545610

611+
/**
612+
* Stores extracted authentication directly on the target, replacing any previous value.
613+
* Inheritance from containing interfaces or namespaces is resolved when querying an operation.
614+
*/
546615
export function setAuthentication(
547616
program: Program,
548617
entity: Namespace | Interface | Operation,
@@ -704,6 +773,10 @@ function extractOAuth2Auth(modelType: Model, data: any): HttpAuth {
704773
};
705774
}
706775

776+
/**
777+
* Reads authentication stored directly on the target, or `undefined` when absent.
778+
* Use {@link getAuthenticationForOperation} to include containing-interface and namespace defaults.
779+
*/
707780
export function getAuthentication(
708781
program: Program,
709782
entity: Namespace | Interface | Operation,

‎packages/http/src/decorators/route.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ export const $route: RouteDecorator = (
3939
});
4040
};
4141

42+
/**
43+
* Records a route fragment and optionally marks an operation as sharing its route.
44+
* Repeated namespace routes must agree; a conflicting namespace fragment reports a diagnostic
45+
* and leaves the original fragment unchanged. Passing `shared: false` does not clear an existing shared mark.
46+
*/
4247
export function setRoute(
4348
context: DecoratorContext,
4449
entity: Operation | Namespace | Interface,

‎packages/http/src/decorators/shared-route.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import { HttpStateKeys } from "../lib.js";
55

66
const [getSharedRoute, setSharedRouteFor] = useStateMap(HttpStateKeys.sharedRoutes);
77

8+
/** Marks an operation as permitting its endpoint to be shared with other shared-route operations. */
89
export function setSharedRoute(program: Program, operation: Operation) {
910
setSharedRouteFor(program, operation, true);
1011
}
1112

13+
/** Returns whether the operation has been marked as sharing its route; false when unmarked. */
1214
export function isSharedRoute(program: Program, operation: Operation): boolean {
1315
return getSharedRoute(program, operation) === true;
1416
}

‎packages/http/src/experimental/merge-patch/helpers.ts‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,36 @@ import { isArrayModelType } from "@typespec/compiler";
33
import { useStateMap } from "@typespec/compiler/utils";
44
import { HttpStateKeys } from "../../lib.js";
55

6+
/** Per-source-property overrides consulted while constructing merge-patch models. */
67
export interface MergePatchPropertyOverrides {
8+
/** Overrides generated optionality in merge mode; absent values use the transform's discriminator-aware default. */
79
optional?: boolean;
10+
/** When false, suppresses null erasure for optional or defaulted source properties; true does not force erasure on other properties. */
811
erasable?: boolean;
12+
/** Recorded merge-versus-replace hint; the current transform does not consult this override. */
913
updateBehavior?: "merge" | "replace";
1014
}
15+
/**
16+
* Reads or replaces a transformed model's source-model association in program state.
17+
* The getter returns `undefined` for an unregistered model; the setter stores the model reference without cloning.
18+
*/
1119
export const [getMergePatchSource, setMergePatchSource] = useStateMap<Model, Model>(
1220
HttpStateKeys.mergePatchModel,
1321
);
1422

23+
/**
24+
* Reads or replaces a transformed property's source-property association.
25+
* The getter returns `undefined` when unregistered; the setter stores the property reference without cloning.
26+
*/
1527
export const [getMergePatchPropertySource, setMergePatchPropertySource] = useStateMap<
1628
ModelProperty,
1729
ModelProperty
1830
>(HttpStateKeys.mergePatchProperty);
1931

32+
/**
33+
* Reads or replaces override settings for a source property during merge-patch transformation.
34+
* The getter returns `undefined` when unset. The setter replaces the stored object rather than merging or cloning it.
35+
*/
2036
export const [getMergePatchPropertyOverrides, setMergePatchPropertyOverrides] = useStateMap<
2137
ModelProperty,
2238
MergePatchPropertyOverrides

‎packages/http/src/experimental/streams.ts‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ try {
1111
};
1212
}
1313

14+
/**
15+
* Separates a stream's wire body type from its logical element type and originating stream model.
16+
* Returned for explicit stream bodies, including properties spread from a stream model.
17+
*/
1418
export interface StreamMetadata {
1519
/**
1620
* The `Type` of the property decorated with `@body`.
@@ -35,7 +39,11 @@ export interface StreamMetadata {
3539
}
3640

3741
/**
38-
* Gets stream metadata for a given `HttpOperationParameters` or `HttpOperationResponseContent`.
42+
* Gets stream metadata for resolved request parameters or a response content alternative.
43+
* Returns `undefined` without a body property, media types, or an originating stream model.
44+
* Follows source-property links so metadata survives model spreads.
45+
*
46+
* Requires `@typespec/streams` to be installed when inspecting a potential stream body.
3947
*/
4048
export function getStreamMetadata(
4149
program: Program,

0 commit comments

Comments
 (0)