umbraco-openapi-client

安装量: 61
排名: #12270

安装

npx skills add https://github.com/umbraco/umbraco-cms-backoffice-skills --skill umbraco-openapi-client
Umbraco OpenAPI Client Setup
CRITICAL: Why This Matters
NEVER use raw
fetch()
calls for Umbraco backoffice API communication.
Raw fetch calls will result in 401 Unauthorized errors because they don't include the bearer token authentication that Umbraco requires.
ALWAYS use a generated OpenAPI client
configured with Umbraco's auth context. This ensures:
Proper bearer token authentication
Type-safe API calls
Automatic token refresh handling
When to Use This
Use this pattern whenever you:
Create custom C# API controllers with
[BackOfficeRoute]
Need to call your custom APIs from the backoffice frontend
Build trees, workspaces, or any UI that loads data from custom endpoints
Setup Overview
The setup has 4 parts:
C# Backend
Controller with Swagger/OpenAPI documentation
Client Dependencies
:
@hey-api/openapi-ts
and
@hey-api/client-fetch
Generation Script
Fetches swagger.json and generates TypeScript client
Entry Point Configuration
Configures client with Umbraco auth Step-by-Step Implementation 1. C# Backend Setup (Swagger/OpenAPI) Your API must be exposed via Swagger. Create a composer: // Composers/MyApiComposer.cs using Asp . Versioning ; using Microsoft . Extensions . Options ; using Microsoft . OpenApi . Models ; using Swashbuckle . AspNetCore . SwaggerGen ; using Umbraco . Cms . Api . Common . OpenApi ; using Umbraco . Cms . Core . Composing ; using Umbraco . Cms . Web . Common . ApplicationBuilder ; namespace MyExtension . Composers ; public class MyApiComposer : IComposer { public void Compose ( IUmbracoBuilder builder ) { // Register the API and Swagger builder . Services . AddSingleton < ISchemaIdHandler , MySchemaIdHandler

( ) ; builder . Services . AddTransient < IConfigureOptions < SwaggerGenOptions

, MySwaggerGenOptions

( ) ; builder . Services . Configure < UmbracoPipelineOptions

( options => { options . AddFilter ( new UmbracoPipelineFilter ( Constants . ApiName ) { SwaggerPath = $"/umbraco/swagger/ { Constants . ApiName . ToLower ( ) } /swagger.json" , SwaggerRoutePrefix = $" { Constants . ApiName . ToLower ( ) } " , } ) ; } ) ; } } // Swagger schema ID handler public class MySchemaIdHandler : SchemaIdHandler { public override bool CanHandle ( Type type ) => type . Namespace ?. StartsWith ( "MyExtension" ) ?? false ; } // Swagger generation options public class MySwaggerGenOptions : IConfigureOptions < SwaggerGenOptions

{ public void Configure ( SwaggerGenOptions options ) { options . SwaggerDoc ( Constants . ApiName , new OpenApiInfo { Title = "My Extension API" , Version = "1.0" , } ) ; } } // Constants public static class Constants { public const string ApiName = "myextension" ; } 2. Client package.json Dependencies Add to your Client/package.json : { "scripts" : { "generate-client" : "node scripts/generate-openapi.js https://localhost:44325/umbraco/swagger/myextension/swagger.json" } , "devDependencies" : { "@hey-api/client-fetch" : "^0.10.0" , "@hey-api/openapi-ts" : "^0.66.7" , "chalk" : "^5.4.1" , "node-fetch" : "^3.3.2" } } 3. Generation Script Create Client/scripts/generate-openapi.js : import fetch from "node-fetch" ; import chalk from "chalk" ; import { createClient , defaultPlugins } from "@hey-api/openapi-ts" ; console . log ( chalk . green ( "Generating OpenAPI client..." ) ) ; const swaggerUrl = process . argv [ 2 ] ; if ( swaggerUrl === undefined ) { console . error ( chalk . red ( ERROR: Missing URL to OpenAPI spec ) ) ; process . exit ( 1 ) ; } // Ignore self-signed certificates on localhost process . env . NODE_TLS_REJECT_UNAUTHORIZED = "0" ; console . log ( Fetching OpenAPI definition from ${ chalk . yellow ( swaggerUrl ) } ) ; fetch ( swaggerUrl ) . then ( async ( response ) => { if ( ! response . ok ) { console . error ( chalk . red ( ERROR: ${ response . status } ${ response . statusText } ) ) ; return ; } await createClient ( { input : swaggerUrl , output : "src/api" , plugins : [ ... defaultPlugins , { name : "@hey-api/client-fetch" , bundle : true , exportFromIndex : true , throwOnError : true , } , { name : "@hey-api/typescript" , enums : "typescript" , } , { name : "@hey-api/sdk" , asClass : true , } , ] , } ) ; console . log ( chalk . green ( "Client generated successfully!" ) ) ; } ) . catch ( ( error ) => { console . error ( ERROR: ${ chalk . red ( error . message ) } ) ; } ) ; 4. Entry Point Configuration (CRITICAL) Configure the generated client with Umbraco's auth context in your entry point: // src/entrypoints/entrypoint.ts import type { UmbEntryPointOnInit , UmbEntryPointOnUnload } from "@umbraco-cms/backoffice/extension-api" ; import { UMB_AUTH_CONTEXT } from "@umbraco-cms/backoffice/auth" ; import { client } from "../api/client.gen.js" ; export const onInit : UmbEntryPointOnInit = ( host , _extensionRegistry ) => { // CRITICAL: Configure the OpenAPI client with authentication host . consumeContext ( UMB_AUTH_CONTEXT , ( authContext ) => { if ( ! authContext ) return ; const config = authContext . getOpenApiConfiguration ( ) ; client . setConfig ( { baseUrl : config . base , credentials : config . credentials , auth : config . token , // This provides the bearer token! } ) ; console . log ( "API client configured with auth" ) ; } ) ; } ; export const onUnload : UmbEntryPointOnUnload = ( _host , _extensionRegistry ) => { // Cleanup if needed } ; 5. Using the Generated Client After running npm run generate-client , use the generated service: // In your workspace context, repository, or data source import { MyExtensionService } from "../api/index.js" ; // The client handles auth automatically! const response = await MyExtensionService . getItems ( { query : { skip : 0 , take : 50 } , } ) ; const item = await MyExtensionService . getItem ( { path : { id : "some-guid" } , } ) ; await MyExtensionService . createItem ( { body : { name : "New Item" , value : 123 } , } ) ; Generation Workflow Start Umbraco - The swagger.json endpoint must be accessible Run generation : npm run generate-client Generated files appear in src/api/ : types.gen.ts - TypeScript types from your C# models sdk.gen.ts - Service class with typed methods client.gen.ts - HTTP client configuration index.ts - Re-exports everything Common Mistakes ❌ WRONG: Raw fetch // This will get 401 Unauthorized! const response = await fetch ( '/umbraco/myextension/api/v1/items' ) ; ❌ WRONG: fetch with credentials only // Still fails - cookies don't work for Management API const response = await fetch ( '/umbraco/myextension/api/v1/items' , { credentials : 'include' } ) ; ✅ CORRECT: Generated OpenAPI client // Client is configured with bearer token in entry point const response = await MyExtensionService . getItems ( ) ; Reference Example See the complete working implementation in: examples/notes-wiki/Client/ - Full OpenAPI client setup examples/tree-example/Client/ - Tree with OpenAPI integration Key Files to Create Composers/MyApiComposer.cs - Swagger registration Client/scripts/generate-openapi.js - Generation script Client/src/entrypoints/entrypoint.ts - Auth configuration Client/src/api/ - Generated (don't edit manually) That's it! Always generate your API client and configure it with auth. Never use raw fetch for authenticated endpoints.

返回排行榜