Generate API clients
You will write a small script that builds the spec and saves it as openapi.json, then
generate a typed client from it. Exporting from a script (rather than fetching from a running
server) lets CI regenerate clients on every commit.
Prerequisites
Section titled “Prerequisites”- A gisila_doc API whose controllers have
operationIdset. Generators name client methods afteroperationId; gisila_doc only emits it when you set it on the verb annotation. - A client generator, for example OpenAPI Generator
(
npx @openapitools/openapi-generator-cli) or any tool that reads OpenAPI 3.1.
1. Give every operation an id
Section titled “1. Give every operation an id”@Get('/{id}', summary: 'Fetch a user', operationId: 'getUser')Future<User> getUser(String id, UserService users) => users.getById(id);2. Build the spec in one place
Section titled “2. Build the spec in one place”Put spec construction in a function both the server and the export script use:
import 'package:gisila_doc/gisila_doc.dart';
import 'controllers/users_controller.dart';
OpenApiSpec newSpec() => OpenApiSpec( info: const ApiInfo(title: 'Users API', version: '1.0.0'), servers: const [ApiServer(url: 'https://api.example.com')], );
/// Attaches every controller. Used by the server and by tool/export_openapi.dart.void attachAll(GisilaApp app, Router router, OpenApiSpec spec, {String prefix = ''}) { UsersController().attachToApp(app, router, spec, prefix: prefix);}3. Write the export script
Section titled “3. Write the export script”attachToApp fills the spec as it registers routes, so you can call it on a throwaway Router
without starting a server:
import 'dart:io';
import 'package:gisila_doc/gisila_doc.dart';import 'package:users_api/api_spec.dart';
void main(List<String> args) { final spec = newSpec(); attachAll(GisilaApp(config: AppConfig()), Router(), spec); final out = args.isEmpty ? 'openapi.json' : args.first; File(out).writeAsStringSync(spec.toJson()); stdout.writeln('Wrote $out');}dart run build_runner builddart run tool/export_openapi.dart build/openapi.json4. Generate a client
Section titled “4. Generate a client”# TypeScript (fetch)npx @openapitools/openapi-generator-cli generate \ -i build/openapi.json -g typescript-fetch -o clients/ts
# Dart (dio)npx @openapitools/openapi-generator-cli generate \ -i build/openapi.json -g dart-dio -o clients/dartCheck your generator’s OpenAPI 3.1 support: gisila_doc expresses nullability as
type: [T, null] (3.1 style), which some older generators do not understand.
5. Or fetch from a running server
Section titled “5. Or fetch from a running server”curl -s https://api.example.com/openapi.json -o openapi.jsonThis works when docsHandler is mounted and
enabled.
Verify it works
Section titled “Verify it works”jq '[.paths[][] | .operationId] | map(select(. == null)) | length' build/openapi.json# 0 -> every operation has an idThe generated client should expose methods such as getUser(id) returning a typed User.
Next steps
Section titled “Next steps”- Describe request and response models so the generated types are precise.
- Document authentication so generated clients add credentials.