API Generator
The API Generator can be used to generate the usual CRUD operations in GraphQL for an entity.
Annotate entity
The API Generator uses the entity and the fields defined within it to generate resolvers, services, inputs, and other
DTOs for the feature. For this, the entity must be annotated with the CrudGenerator decorator:
@CrudGenerator({ targetDirectory: `${__dirname}/../generated/` })
export class Product extends BaseEntity {
...
}
The option targetDirectory specifies the path where the generated files should be written.
For features that should exist only once per scope (e.g., a footer), there is the special CrudSingleGenerator
decorator. The usage of both decorators is the same.
@CrudGenerator() options
| Parameter | Type | Default | Description |
|---|---|---|---|
targetDirectory | string | Required | The directory where the CRUD operations are generated. |
requiredPermission | string[] | string | undefined | Permission(s) required to access the CRUD operations. |
create | boolean | true | If true, includes the "create" operation. |
update | boolean | true | If true, includes the "update" operation. |
delete | boolean | true | If true, includes the "delete" operation. |
list | boolean | true | If true, includes the "list" operation. |
position | object | undefined | Configures the optional magic position field. |
Annotate field
By default, all entities' fields are used for search, filtering, sorting, and input. If you want to change this for a
specific field (e.g., making description not filterable), you can adjust it with the @CrudField decorator.
@CrudField({
search: true,
filter: false,
sort: true,
input: true,
})
description: string;
@CrudField() options
| Parameter | Type | Default | Description |
|---|---|---|---|
search | boolean | true | Specifies if the field should be searchable. |
filter | boolean | true | Specifies if the field should be filterable. |
sort | boolean | true | Specifies if the field should be sortable. |
input | boolean | true | Specifies if the field should be included in input types (e.g., for create/update). |
resolveField | boolean | true | Relevant for relations. Indicates if a field resolver for the relation should be added to the resolver. |
dedicatedResolverArg | boolean | false | Relevant for relations. Adds a dedicated resolver argument for the relation to the create mutation. Otherwise it's included in the input object. |
Generating code
After the entity has been successfully annotated, you can run the API Generator. Newer projects should already have an
api-generator npm script.
If it's still missing, you can add it to api/package.json:
{
...
"scripts": {
"api-generator": "rimraf --glob 'src/**/generated' && comet-api-generator generate",
...
}
}
Now you can run the generator with npm run api-generator. The generated files are located in the specified
targetDirectory.
Although this is generated code, it should still be checked into the repository. This enables a quick start of the API.
Watch Mode
The api-generator script also supports the -w or --watch flag. This will watch for changes in the .entity.ts files and regenerate the corresponding files.
{
...
"scripts": {
"api-generator:watch": "rimraf 'src/*/generated' && comet-api-generator --watch",
...
}
}
Generate only for specific entities
If you want to generate only for specific entities, you can pass a file path to an .entity.ts file with the -f or --file flag
npm exec comet-api-generator -f src/products/entities/product.entity.ts
Register generated resolvers and services
The resolvers and services created by the API Generator must be registered in the corresponding module:
import { ProductsService } from "./generated/products.service";
import { ProductResolver } from "./generated/product.resolver";
@Module({
// ...
providers: [ProductResolver, ProductsService],
})
export class ProductsModule {}
Depending on the magic fields of the entity (e.g., position), the service might not be generated.
Done! The CRUD operations now appear in the GraphQL schema and can be used.
The generated code must be viewed as a self-contained unit and can change incompatibly even between minor versions.
You should not reference the generated code externally (except, of course, to provide the resolver in the module).