Customize SDKs
Edit a generated SDK and keep your changes every time you regenerate it.
You can change a generated SDK the same way you change any other code. Edit the generated files, add files of your own, or remove files you don't need. When you regenerate the SDK later, the APIMatic CLI merges the newly generated code with your version, so your changes are kept and you still get the updates from your API definition.
This works for C#, Python, and TypeScript SDKs. The examples on this page use TypeScript.
If you want to change something your API definition controls, such as a name, a description, or an endpoint, update the definition instead. That way the change shows up in every SDK language and in your developer portal.
Prerequisites
- The APIMatic CLI, installed and signed in. See the Quickstart.
- Git 2.38 or later. Run
git --versionto check.
Customize an SDK
Generate the SDK with the --git-init flag:
apimatic sdk generate --language=typescript --git-initThe --git-init flag turns the SDK directory (sdk/typescript by default) into a Git repository, where the CLI keeps its snapshots. The CLI also writes a .apimatic/generation.json file to the SDK directory. This file records which snapshot the SDK was last generated from, so the next regeneration knows what to merge your changes against. You only need the flag the first time.
The repository has to be at the root of the SDK directory. If the SDK directory is inside another repository, such as your project's, the CLI doesn't use that repository.
If you've already generated the SDK without --git-init, run the command again with the flag before you make any changes. The CLI asks before it overwrites the existing SDK.
Then edit the SDK as you normally would. For example, you could add a helper to a generated model:
export const formatPrice = (book: Book): string => `$${book.price.toFixed(2)}`;You can also add new files, or add dependencies to package.json, the .csproj file, or pyproject.toml. Your changes stay in the SDK directory like any other edit, and you don't have to commit them before you regenerate.
Regenerate the SDK
Regenerate the SDK when you want new generated code, for example after you change your API definition. Run the same command without --git-init:
apimatic sdk generate --language=typescriptLast generation
A snapshot of the code the CLI generated last time
Your SDK
The generated code with your changes
New generation
The code generated from your API definition now
Three-way merge
Finds what you changed and what the generator changed, and keeps both
No overlapping changes
Merged automatically
You both changed the same lines
You choose how to resolve them
Updated SDK
Your changes and the new generated code
The CLI works with three versions of the SDK: the snapshot from the last generation, your version, and the newly generated code. It compares your version and the new code with the snapshot to find the lines you changed and the lines the generator changed, and it keeps both. This is called a three-way merge, and it's the same method Git uses to merge branches. If you and the generator changed the same lines in a file, the CLI asks how to resolve them before it writes anything. See Resolve conflicts.
If the generated code changed, the CLI then lists the files it merged with your changes and the files it left as you wrote them.
Use the same --stability each time. If you change it, the CLI can't merge your changes into the new SDK, and it asks whether to overwrite the SDK instead.
What happens to your changes
| If you | When you regenerate |
|---|---|
| Edited a generated file | The new generated code is merged into your edited version. |
| Added a file | The file is left as it is. |
| Deleted a generated file | The file stays deleted. |
| Moved or renamed a file | Updates to the file are applied at its new location. |
Generated files you haven't changed are replaced with their new versions.
Resolve conflicts
A conflict happens when you and the generator changed the same lines in a file. The CLI checks for conflicts before it writes any files. If it finds any, it lists the affected files and asks how to handle them:
| Option | What happens |
|---|---|
| I'll resolve them myself | The CLI writes the SDK with conflict markers in the affected files. Edit the files to resolve the conflicts, stage them with git add, and run the command again. |
| Resolve using generator changes | Where the changes overlap, the generator's version is used. Your other changes are kept. |
| Resolve using my changes | Where the changes overlap, your version is used. The generator's other updates are still applied. |
| Cancel this run | The CLI stops without writing anything. |
Some conflicts have no markers to edit. For example, if you deleted a file that the generator has since changed, decide whether to keep the file or delete it, and stage that with git add or git rm. The CLI lists these files separately when it tells you what to resolve.
If you run the command again before you've staged every file, the CLI lists the files that are still unresolved. It then asks whether you'll finish resolving them yourself, or whether it should resolve the remaining conflicts using the generator's changes or yours.
To make conflicts less likely, put larger additions in new files and import the generated code from them. A file you add only conflicts if the generator later creates a file at the same path.
Undo a regeneration
If a regeneration merged something you don't want, you can put the SDK back as it was before that run. For example, you might have chosen Resolve using generator changes and lost lines you needed. If you committed your changes before you regenerated, you can also get your version back from the Git history.
Before a regeneration writes merged code into the SDK, the CLI saves the SDK directory as it is, including changes you haven't committed, under the Git ref refs/apimatic/previous. Each regeneration that merges replaces this copy, so you can only undo the most recent one. A run that replaced the SDK instead of merging, such as the first generation with --git-init, doesn't save a copy, so don't use this command after one.
To put the SDK back, run this command in the SDK directory:
git restore --source=refs/apimatic/previous --worktree -- .This restores every file that was in the SDK before the run, including the files the run changed or removed. Files that the run created are left in place. Run git status to find them, and delete the ones you don't want.
If the run left files in conflict, also run git reset, so Git no longer lists them as unresolved. This unstages anything you had staged, but it doesn't change your files.
If the CLI fails partway through writing a regeneration, it uses the same copy to put the SDK back. If it can't, it prints this command for you to run.
Share the SDK with your team
Commit the SDK, including the .apimatic/generation.json file, and push it to a remote repository. Your teammates can clone it into their SDK directory and run the same sdk generate command. Their clone reads .apimatic/generation.json to find the snapshot to merge against, and the CLI fetches that snapshot from the remote if the clone doesn't have it yet.
When you use --git-init, the CLI also adds a pre-push hook to the repository. The hook pushes the CLI's snapshots along with your commits, so everyone on the team merges against the same generated version.
If your project is also a Git repository, add the SDK directory to the project's .gitignore file or add it as a submodule.
Regenerate the SDK in CI
A CI job can't answer the conflict question, so add --force:
npx @apimatic/cli@2 sdk generate --language=typescript --force --auth-key="$APIMATIC_API_KEY"With --force, conflicts are resolved using the generator's changes. If the CLI can't merge the SDK at all, it replaces the SDK and prints a warning. Without --force, the job fails when there's a conflict, and no files are written. The CI image needs Git 2.38 or later.
apimatic sdk publish also merges your changes before it publishes the SDK. When you run it with flags, it always does this. In guided mode, add --git-init. If there are unresolved conflicts, the SDK isn't published.
Troubleshooting
Git is missing or older than 2.38
If Git isn't installed, or is too old, the CLI prints one of these warnings:
git is not available, so your customizations to the generated SDK will not persist across regenerations.git 2.30.2 was found, but 2.38 or newer is needed, so your customizations to the generated SDK will not persist across regenerations.Make sure Git 2.38 or later is installed and on your PATH, then run the command again. If the CLI asks whether to overwrite the SDK, answer no, because overwriting replaces your changes.
The repository is in the middle of a merge
The repository at './sdk/typescript' is in the middle of a merge. Finish it, or abort it with git merge --abort, then rerun.The CLI doesn't regenerate the SDK while Git is in the middle of a merge, rebase, cherry-pick, or revert in the SDK's repository. The message names the one in progress. Finish it, or cancel it with the --abort command from the message, then run the command again.
A clone is missing the snapshot
The snapshot './sdk/typescript' was last generated from is not in its repository, nor on 'origin', so this generation is recorded afresh.This clone doesn't have the snapshot that .apimatic/generation.json names, and the CLI couldn't fetch it from the remote. The end of the message says why: the repository has no remote, the remote doesn't have the snapshot either, or the fetch failed.
If a teammate's clone has the snapshots, answer no when the CLI asks whether to overwrite the SDK. Ask your teammate to push, which sends the snapshots through the pre-push hook, then run the command again. If no clone has them, answer yes. This replaces your changes, and later runs merge against the new generation.
Git doesn't run the pre-push hook
When Git won't run the hook the CLI added, the CLI prints a note titled "Sharing SDK snapshots needs one step". This happens when your repository uses husky or another core.hooksPath setting, or already has a pre-push hook that isn't a shell script. For example:
git runs hooks from './sdk/typescript/.husky/_', so the hook the CLI keeps at './sdk/typescript/.git/hooks/apimatic-pre-push' is not run on push.
1. Add this line to './sdk/typescript/.husky/pre-push':
d="$(git rev-parse --git-common-dir)" && f="$d/hooks/apimatic-pre-push" && [ -f "$f" ] && { t="$d/apimatic-pre-push.$$"; cat >"$t" && sh "$f" "$@" <"$t"; [ -r "$t" ] && command exec <"$t"; rm -f "$t"; } || true
2. Commit it; every clone shares from then on.Add the line to the hook file the note names. If the note asks you to commit the file, commit it, so every clone of the repository shares the snapshots too.
--force replaced the SDK
The new SDK could not be merged into './sdk/typescript', so --force replaced it, and your customizations to it were not carried over. Those you committed are still in its git history, and git -C "./sdk/typescript" diff shows what changed; uncommitted ones are gone.With --force, the CLI replaces the SDK when it can't merge your changes, for example because the snapshot is missing or the stability changed. Run the git diff command from the message to see what was removed, and bring back the changes you committed from the Git history.