SQL OData API Generator
A VS Code extension that generates OData API controllers and repositories from SQL entity C# classes using Scriban templates.
Setup
Each target project needs a SqlODataServiceApiGenerator.json configuration file. Open the Command Palette (Ctrl+Shift+P) and run SQL OData: Create Configuration File to scaffold one, then fill in the fields described below.
Commit the file alongside your project — it stays in your repository and drives all generation for that project.
Configuration — SqlODataServiceApiGenerator.json
{
"sourceDirectory": "relative/path/to/entities",
"outputDirectory": "relative/path/to/output/root",
"templateDirectory": "",
"controller": {
"namespace": "Your.App.Controllers"
},
"repository": {
"namespace": "Your.App.Repositories"
},
"dataContext": {
"type": "Your.App.Services.Data.DataContext"
},
"extraUsings": {
"Controller": [
"Your.App.SomeNamespace"
],
"Repository": [
"Your.App.SomeNamespace"
]
}
}
| Field |
Description |
sourceDirectory |
Path to the folder containing entity .cs files. Relative paths resolve from the config file's location. |
outputDirectory |
Root folder where generated files are written. Controllers/ and Repositories/ subfolders are created automatically. |
templateDirectory |
Path to custom Scriban templates. Leave empty to use the extension's bundled templates. |
controller.namespace |
C# namespace applied to every generated controller file. |
repository.namespace |
C# namespace applied to every generated repository file. |
dataContext.type |
Fully-qualified type name of your data context (e.g. Services.Data.DataContext). |
extraUsings.Controller |
Additional using statements added to generated controller files. |
extraUsings.Repository |
Additional using statements added to generated repository files. |
Running the Generator
Open the Command Palette and run SQL OData: Run Generator.
The extension looks for SqlODataServiceApiGenerator.json in the workspace root. If it is not found there, a file picker opens so you can locate it manually.
Custom Templates
The extension ships with default Scriban templates for controllers and repositories. To customise generation:
- Copy the bundled
Templates folder out of the extension's install directory.
- Set
templateDirectory in your config to point at your copy.
- Edit the
.scriban files as needed.
To override only specific templates, add a file with the .Custom.scriban suffix (e.g. Controller.Custom.scriban) alongside the defaults — the custom variant takes precedence automatically.
Entity Attributes
The generator discovers entities by scanning .cs source files for one of the supported entity attributes. Each attribute serves two purposes: it supplies the plural name used for the OData entity set and generated file names, and it claims an entity type that determines which base controller and repository class are used.
Plural Name
The first string literal passed to any entity attribute becomes the plural name:
[ItemEntity("Suppliers")]
public class Supplier { ... }
// → SuppliersController.cs, SupplierRepository.cs
A second optional string can dictate what claim type to authorize if that that claim type has a different name than the plural name:
[ItemEntity("Suppliers", "Inventory.Suppliers")]
public class Supplier { ... }
// → Inventory.Suppliers.Read
// → Inventory.Suppliers.Create
// → Inventory.Suppliers.Update
// → Inventory.Suppliers.Delete
Entity Type Attributes
| Attribute |
Entity Type |
Base Controller |
Base Repository |
[ItemEntity("PluralName")] |
Item |
ItemController |
ItemRepository |
[LookupItemEntity("PluralName")] |
LookupItem |
LookupItemController |
LookupItemRepository |
[TransactionEntity("PluralName")] |
Transaction |
TransactionController |
TransactionRepository |
[ExtensionEntity("PluralName")] |
Extension |
ExtensionController |
ExtensionRepository |
[IndexEntity("PluralName")] |
Index |
IndexController |
IndexRepository |
[ODataEntity("PluralName")] is also supported. When used, the entity type is inferred from the class's base type:
| Base class |
Inferred Type |
TransactionRow |
Transaction |
ExtensionItem |
Extension |
LookupItem |
LookupItem |
Index |
Index |
| (none / other) |
Item |
If ODataEntity includes a typeof(BaseEntity) argument and no recognized base class is present, the type is inferred as Extension:
[ODataEntity("SupplierAddresses", typeof(Supplier))]
public class SupplierAddress { ... }
Optional Attribute Flags
| Flag |
Effect |
NoController = true |
Skips controller file generation for this entity |
NoRepository = true |
Skips repository file generation for this entity |
[ItemEntity("AuditLogs", NoController = true)]
public class AuditLog { ... }
Requirements
- VS Code 1.85 or later
- The bundled .NET runtime is self-contained — no separate .NET installation required.