Technical manual
...
API documentation
Documenting endpoints
19 min
this guide provides step by step instructions for documenting api endpoints in the ir engine codebase introduction for an overview of how the api documentation system works, see the api architecture docid\ ssz271nsxzzsazahwrxpt guide why good documentation matters while feathers swagger automatically generates basic api documentation, the default output contains only generic placeholders like "creates a new resource with data" that provide little practical value well documented apis are critical for developer experience custom descriptions, examples, and parameter details transform generic documentation into a valuable resource that helps developers understand and use your api effectively generic vs custom documentation example generic (auto generated) { "description" "authentication service", "operations" { "create" { "description" "creates a new resource with data" }, "remove" { "description" "removes a resource with id from the service" } } } improved documentation { "description" "authentication service for user login, token validation, and logout", "operations" { "create" { "description" "authenticates a user with credentials and returns a jwt token", "requestbody" { "content" { "application/json" { "example" { "strategy" "local", "email" "user\@example com", "password" "password123" } } } } } } } documenting an api endpoint follow these steps to document a new api endpoint or improve documentation for an existing one step 1 understand the schema files schema files define the data structure and available methods for a service they are located in packages/common/src/schemas/ let's look at a complete example from packages/common/src/schemas/cluster/build status schema ts // path definition this becomes the api endpoint path export const buildstatuspath = 'build status' // methods definition these determine which http endpoints are available // \['find', 'get', 'create', 'patch', 'remove'] maps to // get /build status (find list all) // get /build status/{id} (get get one by id) // post /build status (create create new) // patch /build status/{id} (patch update) // delete /build status/{id} (remove delete) export const buildstatusmethods = \['find', 'get', 'create', 'patch', 'remove'] as const // main data model schema export const buildstatusschema = type object( { id type integer(), status type string(), datestarted type string(), dateended type string(), logs type string(), commitsha type string(), createdat type string({ format 'date time' }), updatedat type string({ format 'date time' }) }, { $id 'buildstatus', additionalproperties false } ) key elements in schema files path definition export const buildstatuspath = 'build status' this defines the api endpoint path ( /build status ) methods definition export const buildstatusmethods = \['find', 'get', 'create', 'patch', 'remove'] as const this defines which http methods are available for the endpoint each method maps to a specific http operation find → get /build status (list all) get → get /build status/{id} (get one by id) create → post /build status (create new) patch → patch /build status/{id} (update) remove → delete /build status/{id} (delete) schema definitions main schema ( buildstatusschema ) defines the complete data structure data schema ( buildstatusdataschema ) defines fields for creating new entries patch schema ( buildstatuspatchschema ) defines fields for updating entries query schema ( buildstatusqueryschema ) defines available query parameters step 2 enhance schema definitions with descriptions to improve documentation, add descriptions to schema properties continuing with our build status example // main data model schema with added descriptions export const buildstatusschema = type object( { id type integer({ description 'unique identifier for the build status record' }), status type string({ description 'current status of the build (e g , "pending", "in progress", "completed", "failed")' }), datestarted type string({ description 'date and time when the build started' }), dateended type string({ description 'date and time when the build completed or failed' }), logs type string({ description 'build process logs' }), commitsha type string({ description 'git commit sha that triggered the build' }), createdat type string({ format 'date time', description 'when the build status record was created' }), updatedat type string({ format 'date time', description 'when the build status record was last updated' }) }, { $id 'buildstatus', additionalproperties false } ) step 3 create or update the documentation file this is an important step in creating useful api documentation without custom descriptions, your api documentation will only contain generic placeholders that provide little value to api consumers each service has a documentation file that provides additional details these files are located in packages/server core/src/\[category]/\[name]/\[name] docs ts continuing with our build status example, let's look at packages/server core/src/cluster/build status/build status docs ts import { createswaggerserviceoptions } from 'feathers swagger' import { buildstatusdataschema, buildstatuspatchschema, buildstatusqueryschema, buildstatusschema } from '@ir engine/common/src/schemas/cluster/build status schema' export default createswaggerserviceoptions({ schemas { buildstatusdataschema, buildstatuspatchschema, buildstatusqueryschema, buildstatusschema }, docs { description 'build status service description', // generic description securities \['all'] } }) to enhance the documentation, update the docs object with more detailed descriptions and parameter information replace generic descriptions with meaningful, context specific information export default createswaggerserviceoptions({ schemas { buildstatusdataschema, buildstatuspatchschema, buildstatusqueryschema, buildstatusschema }, docs { description 'service for tracking and managing the status of builds in the system', // specific, descriptive securities \['all'], operations { find { description 'retrieves a list of build statuses based on query parameters', // better than generic "retrieves a list of all resources" parameters \[ { in 'query', name 'status', description 'filter builds by status (e g , "pending", "in progress", "completed", "failed")', type 'string' }, { in 'query', name 'commitsha', description 'filter builds by commit sha', type 'string' } ] }, get { description 'retrieves a single build status record by id' // specific to this resource }, create { description 'creates a new build status record to track a build process' // explains purpose, not just action }, patch { description 'updates an existing build status record, typically used to update status or add logs' // explains when/why to use }, remove { description 'deletes a build status record when it is no longer needed' // provides context } } } }) step 4 add examples and response documentation for more comprehensive documentation, add examples of request and response data examples help api consumers understand how to use your api correctly continuing with our build status example export default createswaggerserviceoptions({ schemas { buildstatusdataschema, buildstatuspatchschema, buildstatusqueryschema, buildstatusschema }, docs { description 'service for tracking and managing the status of builds in the system', securities \['all'], operations { find { description 'retrieves a list of build statuses based on query parameters', parameters \[ { in 'query', name 'status', description 'filter builds by status (e g , "pending", "in progress", "completed", "failed")', type 'string' }, { in 'query', name 'commitsha', description 'filter builds by commit sha', type 'string' } ], responses { '200' { description 'successfully retrieved build statuses', content { 'application/json' { example { total 2, limit 10, skip 0, data \[ { id 1, status 'completed', datestarted '2023 04 01t10 00 00z', dateended '2023 04 01t10 15 00z', logs 'build completed successfully', commitsha '8f4b3a1c5d6e7b2a9c0d1e2f3a4b5c6d7e8f9a0b', createdat '2023 04 01t10 00 00z', updatedat '2023 04 01t10 15 00z' }, { id 2, status 'in progress', datestarted '2023 04 01t11 00 00z', dateended null, logs 'building ', commitsha '7e8f9a0b8f4b3a1c5d6e7b2a9c0d1e2f3a4b5c6d', createdat '2023 04 01t11 00 00z', updatedat '2023 04 01t11 00 00z' } ] } } } } } } } } }) step 5 register the service with documentation finally, make sure the documentation is included when registering the service // in packages/server core/src/cluster/build status/build status ts import { buildstatusmethods, buildstatuspath } from '@ir engine/common/src/schemas/cluster/build status schema' import { application } from ' / / /declarations' import { buildstatusservice } from ' /build status class' import buildstatusdocs from ' /build status docs' import hooks from ' /build status hooks' export default (app application) void => { const options = { name buildstatuspath, paginate app get('paginate'), model app get('knexclient'), multi true } app use(buildstatuspath, new buildstatusservice(options), { // a list of all methods this service exposes externally methods buildstatusmethods, // you can add additional custom events to be sent to clients here events \[], docs buildstatusdocs // include the documentation }) const service = app service(buildstatuspath) service hooks(hooks) } step 6 test your documentation after updating the documentation start the server with npm run dev navigate to https //localhost 3030/openapi in your browser find your service in the ui verify that all descriptions, parameters, and examples are correct try out the api using the "try it out" feature note that changes to the openapi documentation require a server restart to be visible in the swagger ui, as feathers needs to rebuild the openapi specification with your changes special cases and advanced options custom parameter names for endpoints like delete /authentication/{accesstoken} where the parameter name isn't the default id , use the idnames property this is an object with path parameter names to customize the idname on operation/method level // in packages/server core/src/user/authentication doc ts export default createswaggerserviceoptions({ schemas {}, docs { description 'authentication service for user login and logout', idnames { remove 'accesstoken' // this defines the parameter name for delete }, idtype 'string', securities \['remove'], // other options } }) for more details on customizing parameter names, see the feathers swagger documentation on idnames https //feathersjs ecosystem github io/feathers swagger/#/api?id=servicedocs custom schemas for services without standard schemas, define them directly in the documentation file // in packages/server core/src/cluster/logs api/logs api docs ts export default createswaggerserviceoptions({ schemas {}, docs { description 'service for logging api events', securities \['all'], definitions { \['logs api'] { type 'object', properties { msg { type 'string', description 'log message' }, level { type 'string', description 'log level (info, warn, error)' } }, additionalproperties { type 'string' } } } } }) for more information on custom schemas and other documentation options, see the feathers swagger documentation on servicedocs https //feathersjs ecosystem github io/feathers swagger/#/api?id=servicedocs special case example authentication service the authentication service demonstrates how to handle custom parameter names // in packages/server core/src/user/authentication doc ts export default createswaggerserviceoptions({ schemas {}, docs { description 'authentication service for user login and logout', idnames { remove 'accesstoken' // this defines the parameter name for delete }, idtype 'string', securities \['remove'], schemas { authrequest { type 'object', properties { strategy { type 'string', default 'jwt', description 'authentication strategy to use' }, accesstoken { type 'string', description 'jwt access token for authentication' } } } }, refs { createrequest 'authrequest', removerequest 'authrequest', createresponse 'authresult', removeresponse 'authresult' }, operations { create { description 'authenticates a user and returns an access token' }, remove { description 'logs out a user by invalidating their access token' } } } }) this example shows custom parameter naming with idnames schema definition directly in the docs object reference mapping with refs clear operation descriptions documentation organization the folder structure in the codebase provides a natural way to organize api endpoints services are grouped by category in the packages/server core/src/ directory, which should be reflected in your documentation when documenting apis, consider how they relate to each other based on their location in the folder structure services in the same category often serve related purposes and may be documented together for better context best practices be specific and contextual replace generic descriptions with meaningful, context specific information include examples provide request and response examples for all operations document parameters thoroughly explain all parameters with clear descriptions include error responses document possible error cases with examples use consistent terminology be consistent in your naming and formatting use sentence case for all headings and descriptions be concise use clear, simple language that's easy to understand explain the "why" describe the purpose and use cases, not just the mechanics document edge cases include limitations and special considerations keep it updated maintain documentation when the api changes think like a user consider what information would be most helpful to api consumers additional resources api architecture docid\ ssz271nsxzzsazahwrxpt overview of the api documentation architecture feathers js documentation https //feathersjs com/api/ official feathers js documentation feathers swagger api documentation https //feathersjs ecosystem github io/feathers swagger/#/api complete reference for all available options openapi specification https //swagger io/specification/ the official openapi specification swagger ui https //swagger io/tools/swagger ui/ documentation on the swagger ui interface